@labdigital/commercetools-mock 0.9.1 → 0.10.1

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 (108) hide show
  1. package/README.md +8 -0
  2. package/dist/index.d.ts +354 -188
  3. package/dist/index.global.js +2346 -2209
  4. package/dist/index.global.js.map +1 -1
  5. package/dist/index.js +1968 -1829
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +2171 -2032
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +30 -21
  10. package/src/constants.ts +4 -2
  11. package/src/ctMock.ts +27 -86
  12. package/src/helpers.ts +10 -11
  13. package/src/index.test.ts +1 -1
  14. package/src/lib/haversine.ts +2 -2
  15. package/src/lib/masking.ts +3 -1
  16. package/src/lib/predicateParser.ts +93 -92
  17. package/src/lib/projectionSearchFilter.test.ts +28 -36
  18. package/src/lib/projectionSearchFilter.ts +88 -103
  19. package/src/oauth/store.ts +3 -3
  20. package/src/priceSelector.test.ts +16 -35
  21. package/src/priceSelector.ts +6 -9
  22. package/src/product-projection-search.ts +49 -57
  23. package/src/projectAPI.test.ts +7 -0
  24. package/src/projectAPI.ts +17 -22
  25. package/src/repositories/abstract.ts +102 -51
  26. package/src/repositories/cart-discount.ts +4 -5
  27. package/src/repositories/cart.ts +56 -46
  28. package/src/repositories/category.ts +23 -26
  29. package/src/repositories/channel.ts +5 -6
  30. package/src/repositories/custom-object.ts +41 -32
  31. package/src/repositories/customer-group.ts +4 -5
  32. package/src/repositories/customer.ts +42 -5
  33. package/src/repositories/discount-code.ts +5 -6
  34. package/src/repositories/errors.ts +10 -14
  35. package/src/repositories/extension.ts +16 -15
  36. package/src/repositories/helpers.ts +10 -15
  37. package/src/repositories/index.ts +75 -0
  38. package/src/repositories/inventory-entry.ts +5 -6
  39. package/src/repositories/my-order.ts +2 -2
  40. package/src/repositories/order-edit.ts +39 -0
  41. package/src/repositories/order.test.ts +16 -11
  42. package/src/repositories/order.ts +21 -14
  43. package/src/repositories/payment.ts +9 -10
  44. package/src/repositories/product-discount.ts +5 -25
  45. package/src/repositories/product-projection.ts +12 -5
  46. package/src/repositories/product-selection.ts +40 -0
  47. package/src/repositories/product-type.ts +38 -60
  48. package/src/repositories/product.ts +128 -85
  49. package/src/repositories/project.ts +16 -33
  50. package/src/repositories/quote-request.ts +28 -0
  51. package/src/repositories/quote.ts +28 -0
  52. package/src/repositories/review.ts +34 -0
  53. package/src/repositories/shipping-method.ts +25 -28
  54. package/src/repositories/shopping-list.ts +6 -6
  55. package/src/repositories/staged-quote.ts +29 -0
  56. package/src/repositories/standalone-price.ts +36 -0
  57. package/src/repositories/state.ts +16 -17
  58. package/src/repositories/store.ts +13 -29
  59. package/src/repositories/subscription.ts +4 -5
  60. package/src/repositories/tax-category.ts +9 -26
  61. package/src/repositories/type.ts +24 -27
  62. package/src/repositories/zone.ts +9 -11
  63. package/src/server.ts +5 -0
  64. package/src/services/abstract.ts +43 -12
  65. package/src/services/cart-discount.ts +3 -4
  66. package/src/services/cart.test.ts +9 -11
  67. package/src/services/cart.ts +42 -38
  68. package/src/services/category.test.ts +1 -2
  69. package/src/services/category.ts +3 -4
  70. package/src/services/channel.ts +3 -4
  71. package/src/services/custom-object.test.ts +6 -6
  72. package/src/services/custom-object.ts +4 -5
  73. package/src/services/customer-group.ts +3 -4
  74. package/src/services/customer.test.ts +136 -0
  75. package/src/services/customer.ts +5 -6
  76. package/src/services/discount-code.ts +3 -4
  77. package/src/services/extension.ts +3 -4
  78. package/src/services/index.ts +74 -0
  79. package/src/services/inventory-entry.test.ts +9 -13
  80. package/src/services/inventory-entry.ts +3 -4
  81. package/src/services/my-cart.test.ts +2 -0
  82. package/src/services/my-cart.ts +4 -5
  83. package/src/services/my-customer.ts +3 -4
  84. package/src/services/my-order.ts +4 -5
  85. package/src/services/my-payment.ts +3 -4
  86. package/src/services/order.test.ts +28 -26
  87. package/src/services/order.ts +4 -5
  88. package/src/services/payment.ts +3 -4
  89. package/src/services/product-discount.ts +3 -20
  90. package/src/services/product-projection.test.ts +76 -8
  91. package/src/services/product-projection.ts +4 -5
  92. package/src/services/product-type.ts +3 -20
  93. package/src/services/product.test.ts +200 -90
  94. package/src/services/product.ts +3 -4
  95. package/src/services/project.ts +5 -6
  96. package/src/services/shipping-method.ts +3 -4
  97. package/src/services/shopping-list.ts +3 -4
  98. package/src/services/state.ts +3 -4
  99. package/src/services/store.test.ts +11 -2
  100. package/src/services/store.ts +4 -21
  101. package/src/services/subscription.ts +3 -4
  102. package/src/services/tax-category.ts +3 -20
  103. package/src/services/type.ts +3 -4
  104. package/src/services/zone.ts +3 -4
  105. package/src/storage/abstract.ts +82 -0
  106. package/src/{storage.ts → storage/in-memory.ts} +79 -147
  107. package/src/storage/index.ts +2 -0
  108. package/src/types.ts +52 -83
package/dist/index.js CHANGED
@@ -37,9 +37,56 @@ var import_express6 = __toESM(require("express"));
37
37
  var import_supertest = __toESM(require("supertest"));
38
38
  var import_morgan = __toESM(require("morgan"));
39
39
 
40
- // src/storage.ts
40
+ // src/storage/abstract.ts
41
+ var AbstractStorage = class {
42
+ };
43
+
44
+ // src/storage/in-memory.ts
41
45
  var import_assert = __toESM(require("assert"));
42
46
 
47
+ // src/exceptions.ts
48
+ var CommercetoolsError = class extends Error {
49
+ constructor(info, statusCode = 400) {
50
+ super(info.message);
51
+ this.info = info;
52
+ this.statusCode = statusCode || 500;
53
+ }
54
+ };
55
+
56
+ // src/helpers.ts
57
+ var import_uuid = require("uuid");
58
+ var getBaseResourceProperties = () => ({
59
+ id: (0, import_uuid.v4)(),
60
+ createdAt: new Date().toISOString(),
61
+ lastModifiedAt: new Date().toISOString(),
62
+ version: 0
63
+ });
64
+ var nestedLookup = (obj, path) => {
65
+ if (!path || path === "") {
66
+ return obj;
67
+ }
68
+ const parts = path.split(".");
69
+ let val = obj;
70
+ for (let i = 0; i < parts.length; i++) {
71
+ const part = parts[i];
72
+ if (val == void 0) {
73
+ return void 0;
74
+ }
75
+ val = val[part];
76
+ }
77
+ return val;
78
+ };
79
+ var QueryParamsAsArray = (input) => {
80
+ if (input == void 0) {
81
+ return [];
82
+ }
83
+ if (Array.isArray(input)) {
84
+ return input;
85
+ }
86
+ return [input];
87
+ };
88
+ var cloneObject = (o) => JSON.parse(JSON.stringify(o));
89
+
43
90
  // src/lib/expandParser.ts
44
91
  var parseExpandClause = (clause) => {
45
92
  const result = {
@@ -70,8 +117,8 @@ var haversineDistance = (src, dst) => {
70
117
  const toRadian = (deg) => deg * (Math.PI / 180);
71
118
  const dLat = toRadian(dst.latitude - src.latitude);
72
119
  const dLon = toRadian(dst.longitude - src.longitude);
73
- var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRadian(src.latitude)) * Math.cos(toRadian(dst.latitude)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
74
- var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
120
+ const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRadian(src.latitude)) * Math.cos(toRadian(dst.latitude)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
121
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
75
122
  return RADIUS_OF_EARTH_IN_KM * c * 1e3;
76
123
  };
77
124
 
@@ -84,9 +131,7 @@ var PredicateError = class {
84
131
  var parseQueryExpression = (predicate) => {
85
132
  if (Array.isArray(predicate)) {
86
133
  const callbacks = predicate.map((item) => generateMatchFunc(item));
87
- return (target, variables) => {
88
- return callbacks.every((callback) => callback(target, variables));
89
- };
134
+ return (target, variables) => callbacks.every((callback) => callback(target, variables));
90
135
  } else {
91
136
  return generateMatchFunc(predicate);
92
137
  }
@@ -126,66 +171,66 @@ var resolveValue = (obj, val) => {
126
171
  }
127
172
  return obj[val.value];
128
173
  };
129
- var getLexer = (value) => {
130
- return new import_perplex.default(value).token("AND", /and(?![-_a-z0-9]+)/i).token("OR", /or(?![-_a-z0-9]+)/i).token("NOT", /not(?![-_a-z0-9]+)/i).token("WITHIN", /within(?![-_a-z0-9]+)/i).token("IN", /in(?![-_a-z0-9]+)/i).token("MATCHES_IGNORE_CASE", /matches\s+ignore\s+case(?![-_a-z0-9]+)/i).token("CONTAINS", /contains(?![-_a-z0-9]+)/i).token("ALL", /all(?![-_a-z0-9]+)/i).token("ANY", /any(?![-_a-z0-9]+)/i).token("EMPTY", /empty(?![-_a-z0-9]+)/i).token("IS", /is(?![-_a-z0-9]+)/i).token("DEFINED", /defined(?![-_a-z0-9]+)/i).token("FLOAT", /\d+\.\d+/).token("INT", /\d+/).token("VARIABLE", /:([-_A-Za-z0-9]+)/).token("BOOLEAN", /(true|false)/).token("IDENTIFIER", /[-_A-Za-z0-9]+/).token("STRING", /"((?:\\.|[^"\\])*)"/).token("STRING", /'((?:\\.|[^'\\])*)'/).token("COMMA", ",").token("(", "(").token(")", ")").token(">=", ">=").token("<=", "<=").token(">", ">").token("<", "<").token("!=", "!=").token("=", "=").token('"', '"').token("WS", /\s+/, true);
131
- };
174
+ var getLexer = (value) => new import_perplex.default(value).token("AND", /and(?![-_a-z0-9]+)/i).token("OR", /or(?![-_a-z0-9]+)/i).token("NOT", /not(?![-_a-z0-9]+)/i).token("WITHIN", /within(?![-_a-z0-9]+)/i).token("IN", /in(?![-_a-z0-9]+)/i).token("MATCHES_IGNORE_CASE", /matches\s+ignore\s+case(?![-_a-z0-9]+)/i).token("CONTAINS", /contains(?![-_a-z0-9]+)/i).token("ALL", /all(?![-_a-z0-9]+)/i).token("ANY", /any(?![-_a-z0-9]+)/i).token("EMPTY", /empty(?![-_a-z0-9]+)/i).token("IS", /is(?![-_a-z0-9]+)/i).token("DEFINED", /defined(?![-_a-z0-9]+)/i).token("FLOAT", /\d+\.\d+/).token("INT", /\d+/).token("VARIABLE", /:([-_A-Za-z0-9]+)/).token("BOOLEAN", /(true|false)/).token("IDENTIFIER", /[-_A-Za-z0-9]+/).token("STRING", /"((?:\\.|[^"\\])*)"/).token("STRING", /'((?:\\.|[^'\\])*)'/).token("COMMA", ",").token("(", "(").token(")", ")").token(">=", ">=").token("<=", "<=").token(">", ">").token("<", "<").token("!=", "!=").token("=", "=").token('"', '"').token("WS", /\s+/, true);
132
175
  var generateMatchFunc = (predicate) => {
133
176
  const lexer = getLexer(predicate);
134
- const parser = new import_pratt.Parser(lexer).builder().nud("IDENTIFIER", 100, (t) => {
135
- return {
177
+ const parser = new import_pratt.Parser(lexer).builder().nud(
178
+ "IDENTIFIER",
179
+ 100,
180
+ (t) => ({
136
181
  type: "identifier",
137
182
  value: t.token.match,
138
183
  pos: t.token.strpos()
139
- };
140
- }).nud("BOOLEAN", 1, (t) => {
141
- return {
184
+ })
185
+ ).nud(
186
+ "BOOLEAN",
187
+ 1,
188
+ (t) => ({
142
189
  type: "boolean",
143
190
  value: t.token.match === "true" ? true : false,
144
191
  pos: t.token.strpos()
145
- };
146
- }).nud("VARIABLE", 100, (t) => {
147
- return {
192
+ })
193
+ ).nud(
194
+ "VARIABLE",
195
+ 100,
196
+ (t) => ({
148
197
  type: "var",
149
198
  value: t.token.groups[1],
150
199
  pos: t.token.strpos()
151
- };
152
- }).nud("STRING", 100, (t) => {
153
- return {
200
+ })
201
+ ).nud(
202
+ "STRING",
203
+ 100,
204
+ (t) => ({
154
205
  type: "string",
155
206
  value: t.token.groups[1],
156
207
  pos: t.token.strpos()
157
- };
158
- }).nud("INT", 1, (t) => {
159
- return {
208
+ })
209
+ ).nud(
210
+ "INT",
211
+ 1,
212
+ (t) => ({
160
213
  type: "int",
161
214
  value: parseInt(t.token.match, 10),
162
215
  pos: t.token.strpos()
163
- };
164
- }).nud("FLOAT", 1, (t) => {
165
- return {
216
+ })
217
+ ).nud(
218
+ "FLOAT",
219
+ 1,
220
+ (t) => ({
166
221
  type: "float",
167
222
  value: parseFloat(t.token.match),
168
223
  pos: t.token.strpos()
169
- };
170
- }).nud("NOT", 100, ({ bp }) => {
224
+ })
225
+ ).nud("NOT", 100, ({ bp }) => {
171
226
  const expr = parser.parse({ terminals: [bp - 1] });
172
- return (obj) => {
173
- return !expr(obj);
174
- };
175
- }).nud("EMPTY", 10, ({ bp }) => {
176
- return "empty";
177
- }).nud("DEFINED", 10, ({ bp }) => {
178
- return "defined";
179
- }).led("AND", 5, ({ left, bp }) => {
227
+ return (obj) => !expr(obj);
228
+ }).nud("EMPTY", 10, ({ bp }) => "empty").nud("DEFINED", 10, ({ bp }) => "defined").led("AND", 5, ({ left, bp }) => {
180
229
  const expr = parser.parse({ terminals: [bp - 1] });
181
- return (obj) => {
182
- return left(obj) && expr(obj);
183
- };
230
+ return (obj) => left(obj) && expr(obj);
184
231
  }).led("OR", 5, ({ left, token, bp }) => {
185
232
  const expr = parser.parse({ terminals: [bp - 1] });
186
- return (obj, vars) => {
187
- return left(obj, vars) || expr(obj, vars);
188
- };
233
+ return (obj, vars) => left(obj, vars) || expr(obj, vars);
189
234
  }).led("COMMA", 1, ({ left, token, bp }) => {
190
235
  const expr = parser.parse({ terminals: [bp - 1] });
191
236
  if (Array.isArray(expr)) {
@@ -220,33 +265,23 @@ var generateMatchFunc = (predicate) => {
220
265
  }).led("!=", 20, ({ left, bp }) => {
221
266
  const expr = parser.parse({ terminals: [bp - 1] });
222
267
  validateSymbol(expr);
223
- return (obj, vars) => {
224
- return resolveValue(obj, left) !== resolveSymbol(expr, vars);
225
- };
268
+ return (obj, vars) => resolveValue(obj, left) !== resolveSymbol(expr, vars);
226
269
  }).led(">", 20, ({ left, bp }) => {
227
270
  const expr = parser.parse({ terminals: [bp - 1] });
228
271
  validateSymbol(expr);
229
- return (obj, vars) => {
230
- return resolveValue(obj, left) > resolveSymbol(expr, vars);
231
- };
272
+ return (obj, vars) => resolveValue(obj, left) > resolveSymbol(expr, vars);
232
273
  }).led(">=", 20, ({ left, bp }) => {
233
274
  const expr = parser.parse({ terminals: [bp - 1] });
234
275
  validateSymbol(expr);
235
- return (obj, vars) => {
236
- return resolveValue(obj, left) >= resolveSymbol(expr, vars);
237
- };
276
+ return (obj, vars) => resolveValue(obj, left) >= resolveSymbol(expr, vars);
238
277
  }).led("<", 20, ({ left, bp }) => {
239
278
  const expr = parser.parse({ terminals: [bp - 1] });
240
279
  validateSymbol(expr);
241
- return (obj, vars) => {
242
- return resolveValue(obj, left) < resolveSymbol(expr, vars);
243
- };
280
+ return (obj, vars) => resolveValue(obj, left) < resolveSymbol(expr, vars);
244
281
  }).led("<=", 20, ({ left, bp }) => {
245
282
  const expr = parser.parse({ terminals: [bp - 1] });
246
283
  validateSymbol(expr);
247
- return (obj, vars) => {
248
- return resolveValue(obj, left) <= resolveSymbol(expr, vars);
249
- };
284
+ return (obj, vars) => resolveValue(obj, left) <= resolveSymbol(expr, vars);
250
285
  }).led("IS", 20, ({ left, bp }) => {
251
286
  let invert = false;
252
287
  const next = lexer.peek();
@@ -369,18 +404,7 @@ var generateMatchFunc = (predicate) => {
369
404
  return result;
370
405
  };
371
406
 
372
- // src/exceptions.ts
373
- var CommercetoolsError = class extends Error {
374
- constructor(info, statusCode = 400) {
375
- super(info.message);
376
- this.info = info;
377
- this.statusCode = statusCode || 500;
378
- }
379
- };
380
-
381
- // src/storage.ts
382
- var AbstractStorage = class {
383
- };
407
+ // src/storage/in-memory.ts
384
408
  var InMemoryStorage = class extends AbstractStorage {
385
409
  constructor() {
386
410
  super(...arguments);
@@ -420,13 +444,11 @@ var InMemoryStorage = class extends AbstractStorage {
420
444
  this.projects[project.key] = project;
421
445
  return project;
422
446
  };
423
- this.getProject = (projectKey) => {
424
- return this.addProject(projectKey);
425
- };
447
+ this.getProject = (projectKey) => this.addProject(projectKey);
426
448
  this.expand = (projectKey, obj, clause) => {
427
449
  if (!clause)
428
450
  return obj;
429
- const newObj = JSON.parse(JSON.stringify(obj));
451
+ const newObj = cloneObject(obj);
430
452
  if (Array.isArray(clause)) {
431
453
  clause.forEach((c) => {
432
454
  this._resolveResource(projectKey, newObj, c);
@@ -478,13 +500,15 @@ var InMemoryStorage = class extends AbstractStorage {
478
500
  "order-edit": /* @__PURE__ */ new Map(),
479
501
  payment: /* @__PURE__ */ new Map(),
480
502
  product: /* @__PURE__ */ new Map(),
503
+ quote: /* @__PURE__ */ new Map(),
504
+ "quote-request": /* @__PURE__ */ new Map(),
481
505
  "product-discount": /* @__PURE__ */ new Map(),
482
- "product-price": /* @__PURE__ */ new Map(),
483
506
  "product-selection": /* @__PURE__ */ new Map(),
484
507
  "product-type": /* @__PURE__ */ new Map(),
485
508
  "product-projection": /* @__PURE__ */ new Map(),
486
509
  review: /* @__PURE__ */ new Map(),
487
510
  "shipping-method": /* @__PURE__ */ new Map(),
511
+ "staged-quote": /* @__PURE__ */ new Map(),
488
512
  state: /* @__PURE__ */ new Map(),
489
513
  store: /* @__PURE__ */ new Map(),
490
514
  "shopping-list": /* @__PURE__ */ new Map(),
@@ -504,12 +528,10 @@ var InMemoryStorage = class extends AbstractStorage {
504
528
  }
505
529
  }
506
530
  }
507
- assertStorage(typeId) {
508
- }
509
531
  all(projectKey, typeId) {
510
532
  const store = this.forProjectKey(projectKey)[typeId];
511
533
  if (store) {
512
- return Array.from(store.values());
534
+ return Array.from(store.values()).map(cloneObject);
513
535
  }
514
536
  return [];
515
537
  }
@@ -519,13 +541,14 @@ var InMemoryStorage = class extends AbstractStorage {
519
541
  (_a = store[typeId]) == null ? void 0 : _a.set(obj.id, obj);
520
542
  const resource = this.get(projectKey, typeId, obj.id, params);
521
543
  (0, import_assert.default)(resource, `resource of type ${typeId} with id ${obj.id} not created`);
522
- return resource;
544
+ return cloneObject(resource);
523
545
  }
524
546
  get(projectKey, typeId, id, params = {}) {
525
547
  var _a;
526
548
  const resource = (_a = this.forProjectKey(projectKey)[typeId]) == null ? void 0 : _a.get(id);
527
549
  if (resource) {
528
- return this.expand(projectKey, resource, params.expand);
550
+ const clone = cloneObject(resource);
551
+ return this.expand(projectKey, clone, params.expand);
529
552
  }
530
553
  return null;
531
554
  }
@@ -538,7 +561,8 @@ var InMemoryStorage = class extends AbstractStorage {
538
561
  const resources = Array.from(resourceStore.values());
539
562
  const resource = resources.find((e) => e.key === key);
540
563
  if (resource) {
541
- return this.expand(projectKey, resource, params.expand);
564
+ const clone = cloneObject(resource);
565
+ return this.expand(projectKey, clone, params.expand);
542
566
  }
543
567
  return null;
544
568
  }
@@ -556,7 +580,7 @@ var InMemoryStorage = class extends AbstractStorage {
556
580
  if (!store) {
557
581
  throw new Error("No type");
558
582
  }
559
- let resources = Array.from(store.values());
583
+ let resources = this.all(projectKey, typeId);
560
584
  if (params.where) {
561
585
  try {
562
586
  const filterFunc = parseQueryExpression(params.where);
@@ -576,24 +600,20 @@ var InMemoryStorage = class extends AbstractStorage {
576
600
  const limit = params.limit || 20;
577
601
  resources = resources.slice(offset, offset + limit);
578
602
  if (params.expand !== void 0) {
579
- resources = resources.map((resource) => {
580
- return this.expand(projectKey, resource, params.expand);
581
- });
603
+ resources = resources.map(
604
+ (resource) => this.expand(projectKey, resource, params.expand)
605
+ );
582
606
  }
583
607
  return {
584
608
  count: totalResources,
585
609
  total: resources.length,
586
610
  offset,
587
611
  limit,
588
- results: resources
612
+ results: resources.map(cloneObject)
589
613
  };
590
614
  }
591
615
  search(projectKey, typeId, params) {
592
- const store = this.forProjectKey(projectKey)[typeId];
593
- if (!store) {
594
- throw new Error("No type");
595
- }
596
- let resources = Array.from(store.values());
616
+ let resources = this.all(projectKey, typeId);
597
617
  if (params.where) {
598
618
  try {
599
619
  const filterFunc = parseQueryExpression(params.where);
@@ -613,9 +633,9 @@ var InMemoryStorage = class extends AbstractStorage {
613
633
  const limit = params.limit || 20;
614
634
  resources = resources.slice(offset, offset + limit);
615
635
  if (params.expand !== void 0) {
616
- resources = resources.map((resource) => {
617
- return this.expand(projectKey, resource, params.expand);
618
- });
636
+ resources = resources.map(
637
+ (resource) => this.expand(projectKey, resource, params.expand)
638
+ );
619
639
  }
620
640
  return {
621
641
  count: totalResources,
@@ -634,7 +654,7 @@ var InMemoryStorage = class extends AbstractStorage {
634
654
  console.error(
635
655
  `No resource found with typeId=${identifier.typeId}, id=${identifier.id}`
636
656
  );
637
- return void 0;
657
+ return null;
638
658
  }
639
659
  if (identifier.key) {
640
660
  const store = this.forProjectKey(projectKey)[identifier.typeId];
@@ -651,7 +671,7 @@ var InMemoryStorage = class extends AbstractStorage {
651
671
  );
652
672
  }
653
673
  }
654
- return void 0;
674
+ return null;
655
675
  }
656
676
  _resolveReference(projectKey, reference, expand) {
657
677
  if (reference === void 0)
@@ -816,51 +836,16 @@ var OAuth2Server = class {
816
836
  }
817
837
  };
818
838
 
819
- // src/helpers.ts
820
- var import_uuid = require("uuid");
821
- var getBaseResourceProperties = () => {
822
- return {
823
- id: (0, import_uuid.v4)(),
824
- createdAt: new Date().toISOString(),
825
- lastModifiedAt: new Date().toISOString(),
826
- version: 0
827
- };
828
- };
829
- var nestedLookup = (obj, path) => {
830
- if (!path || path === "") {
831
- return obj;
832
- }
833
- const parts = path.split(".");
834
- let val = obj;
835
- for (let i = 0; i < parts.length; i++) {
836
- const part = parts[i];
837
- if (val == void 0) {
838
- return void 0;
839
- }
840
- val = val[part];
841
- }
842
- return val;
843
- };
844
- var QueryParamsAsArray = (input) => {
845
- if (input == void 0) {
846
- return [];
847
- }
848
- if (Array.isArray(input)) {
849
- return input;
850
- }
851
- return [input];
852
- };
853
-
854
839
  // src/projectAPI.ts
855
840
  var ProjectAPI = class {
856
- constructor(projectKey, services, storage) {
841
+ constructor(projectKey, repositories, storage) {
857
842
  this.projectKey = projectKey;
858
843
  this._storage = storage;
859
- this._services = services;
844
+ this._repositories = repositories;
860
845
  }
861
846
  add(typeId, resource) {
862
- const service = this._services[typeId];
863
- if (service) {
847
+ const repository = this._repositories[typeId];
848
+ if (repository) {
864
849
  this._storage.add(this.projectKey, typeId, {
865
850
  ...getBaseResourceProperties(),
866
851
  ...resource
@@ -878,9 +863,9 @@ var ProjectAPI = class {
878
863
  );
879
864
  }
880
865
  getRepository(typeId) {
881
- const service = this._services[typeId];
882
- if (service !== void 0) {
883
- return service.repository;
866
+ const repository = this._repositories[typeId];
867
+ if (repository !== void 0) {
868
+ return repository;
884
869
  }
885
870
  throw new Error("No such repository");
886
871
  }
@@ -902,9 +887,6 @@ var copyHeaders = (headers) => {
902
887
  var DEFAULT_API_HOSTNAME = /^https:\/\/api\..*?\.commercetools.com:443$/;
903
888
  var DEFAULT_AUTH_HOSTNAME = /^https:\/\/auth\..*?\.commercetools.com:443$/;
904
889
 
905
- // src/services/abstract.ts
906
- var import_express2 = require("express");
907
-
908
890
  // src/repositories/helpers.ts
909
891
  var import_uuid2 = require("uuid");
910
892
  var createAddress = (base, projectKey, storage) => {
@@ -943,12 +925,10 @@ var createCustomFields = (draft, projectKey, storage) => {
943
925
  fields: draft.fields
944
926
  };
945
927
  };
946
- var createPrice = (draft) => {
947
- return {
948
- id: (0, import_uuid2.v4)(),
949
- value: createTypedMoney(draft.value)
950
- };
951
- };
928
+ var createPrice = (draft) => ({
929
+ id: (0, import_uuid2.v4)(),
930
+ value: createTypedMoney(draft.value)
931
+ });
952
932
  var createTypedMoney = (value) => {
953
933
  let fractionDigits = 2;
954
934
  switch (value.currencyCode.toUpperCase()) {
@@ -1030,143 +1010,58 @@ var getReferenceFromResourceIdentifier = (resourceIdentifier, projectKey, storag
1030
1010
  id: resource == null ? void 0 : resource.id
1031
1011
  };
1032
1012
  };
1033
- var getRepositoryContext = (request) => {
1034
- return {
1035
- projectKey: request.params.projectKey,
1036
- storeKey: request.params.storeKey
1037
- };
1038
- };
1013
+ var getRepositoryContext = (request) => ({
1014
+ projectKey: request.params.projectKey,
1015
+ storeKey: request.params.storeKey
1016
+ });
1039
1017
 
1040
- // src/services/abstract.ts
1041
- var AbstractService = class {
1042
- constructor(parent) {
1043
- this.createStatusCode = 201;
1018
+ // src/services/project.ts
1019
+ var ProjectService = class {
1020
+ constructor(parent, repository) {
1021
+ this.repository = repository;
1044
1022
  this.registerRoutes(parent);
1045
1023
  }
1046
- extraRoutes(router) {
1047
- }
1048
1024
  registerRoutes(parent) {
1049
- const basePath = this.getBasePath();
1050
- const router = (0, import_express2.Router)({ mergeParams: true });
1051
- this.extraRoutes(router);
1052
- router.get("/", this.get.bind(this));
1053
- router.get("/key=:key", this.getWithKey.bind(this));
1054
- router.get("/:id", this.getWithId.bind(this));
1055
- router.delete("/key=:key", this.deletewithKey.bind(this));
1056
- router.delete("/:id", this.deletewithId.bind(this));
1057
- router.post("/", this.post.bind(this));
1058
- router.post("/key=:key", this.postWithKey.bind(this));
1059
- router.post("/:id", this.postWithId.bind(this));
1060
- parent.use(`/${basePath}`, router);
1025
+ parent.get("", this.get.bind(this));
1026
+ parent.post("", this.post.bind(this));
1061
1027
  }
1062
1028
  get(request, response) {
1063
- const limit = this._parseParam(request.query.limit);
1064
- const offset = this._parseParam(request.query.offset);
1065
- const result = this.repository.query(getRepositoryContext(request), {
1066
- expand: this._parseParam(request.query.expand),
1067
- where: this._parseParam(request.query.where),
1068
- limit: limit !== void 0 ? Number(limit) : void 0,
1069
- offset: offset !== void 0 ? Number(offset) : void 0
1070
- });
1071
- return response.status(200).send(result);
1072
- }
1073
- getWithId(request, response) {
1074
- const result = this._expandWithId(request, request.params["id"]);
1075
- if (!result) {
1076
- return response.status(404).send();
1077
- }
1078
- return response.status(200).send(result);
1079
- }
1080
- getWithKey(request, response) {
1081
- const result = this.repository.getByKey(
1082
- getRepositoryContext(request),
1083
- request.params["key"],
1084
- { expand: this._parseParam(request.query.expand) }
1085
- );
1086
- if (!result)
1087
- return response.status(404).send();
1088
- return response.status(200).send(result);
1089
- }
1090
- deletewithId(request, response) {
1091
- const result = this.repository.delete(
1092
- getRepositoryContext(request),
1093
- request.params["id"],
1094
- {
1095
- expand: this._parseParam(request.query.expand)
1096
- }
1097
- );
1098
- if (!result) {
1099
- return response.status(404).send("Not found");
1100
- }
1101
- return response.status(200).send(result);
1102
- }
1103
- deletewithKey(request, response) {
1104
- return response.status(500).send("Not implemented");
1029
+ const project = this.repository.get(getRepositoryContext(request));
1030
+ return response.status(200).send(project);
1105
1031
  }
1106
1032
  post(request, response) {
1107
- const draft = request.body;
1108
- const resource = this.repository.create(
1109
- getRepositoryContext(request),
1110
- draft
1111
- );
1112
- const result = this._expandWithId(request, resource.id);
1113
- return response.status(this.createStatusCode).send(result);
1114
- }
1115
- postWithId(request, response) {
1116
1033
  const updateRequest = request.body;
1117
- const resource = this.repository.get(
1118
- getRepositoryContext(request),
1119
- request.params["id"]
1120
- );
1121
- if (!resource) {
1122
- return response.status(404).send("Not found");
1123
- }
1124
- if (resource.version !== updateRequest.version) {
1125
- return response.status(409).send("Concurrent modification");
1034
+ const project = this.repository.get(getRepositoryContext(request));
1035
+ if (!project) {
1036
+ return response.status(404).send({});
1126
1037
  }
1127
- const updatedResource = this.repository.processUpdateActions(
1038
+ this.repository.processUpdateActions(
1128
1039
  getRepositoryContext(request),
1129
- resource,
1040
+ project,
1041
+ updateRequest.version,
1130
1042
  updateRequest.actions
1131
1043
  );
1132
- const result = this._expandWithId(request, updatedResource.id);
1133
- return response.status(200).send(result);
1134
- }
1135
- postWithKey(request, response) {
1136
- return response.status(500).send("Not implemented");
1137
- }
1138
- _expandWithId(request, resourceId) {
1139
- const result = this.repository.get(
1140
- getRepositoryContext(request),
1141
- resourceId,
1142
- {
1143
- expand: this._parseParam(request.query.expand)
1144
- }
1145
- );
1146
- return result;
1147
- }
1148
- _parseParam(value) {
1149
- if (Array.isArray(value)) {
1150
- return value;
1151
- } else if (value !== void 0) {
1152
- return [`${value}`];
1153
- }
1154
- return void 0;
1044
+ return response.status(200).send({});
1155
1045
  }
1156
1046
  };
1157
1047
 
1048
+ // src/repositories/cart.ts
1049
+ var import_uuid3 = require("uuid");
1050
+
1158
1051
  // src/repositories/abstract.ts
1159
1052
  var import_deep_equal = __toESM(require("deep-equal"));
1160
1053
 
1161
1054
  // src/repositories/errors.ts
1162
- var checkConcurrentModification = (resource, expectedVersion) => {
1163
- if (resource.version === expectedVersion)
1055
+ var checkConcurrentModification = (currentVersion, expectedVersion, identifier) => {
1056
+ if (currentVersion === expectedVersion)
1164
1057
  return;
1165
- const identifier = resource.id ? resource.id : resource.key;
1058
+ console.error(
1059
+ `Object ${identifier} has a different version than expected. Expected: ${expectedVersion} - Actual: ${currentVersion}.`
1060
+ );
1166
1061
  throw new CommercetoolsError(
1167
1062
  {
1168
- message: `Object ${identifier} has a different version than expected. Expected: ${expectedVersion} - Actual: ${resource.version}.`,
1169
- currentVersion: resource.version,
1063
+ message: `Object ${identifier} has a different version than expected. Expected: ${expectedVersion} - Actual: ${currentVersion}.`,
1064
+ currentVersion,
1170
1065
  code: "ConcurrentModification"
1171
1066
  },
1172
1067
  409
@@ -1179,36 +1074,43 @@ var AbstractRepository = class {
1179
1074
  this.actions = {};
1180
1075
  this._storage = storage;
1181
1076
  }
1182
- processUpdateActions(context, resource, actions) {
1183
- const modifiedResource = JSON.parse(JSON.stringify(resource));
1077
+ processUpdateActions(context, resource, version, actions) {
1078
+ const updatedResource = cloneObject(resource);
1079
+ const identifier = resource.id ? resource.id : resource.key;
1184
1080
  actions.forEach((action) => {
1185
1081
  const updateFunc = this.actions[action.action];
1186
1082
  if (!updateFunc) {
1187
1083
  console.error(`No mock implemented for update action ${action.action}`);
1188
- return;
1084
+ throw new Error(
1085
+ `No mock implemented for update action ${action.action}`
1086
+ );
1087
+ }
1088
+ const beforeUpdate = cloneObject(resource);
1089
+ updateFunc(context, updatedResource, action);
1090
+ if (!(0, import_deep_equal.default)(beforeUpdate, updatedResource)) {
1091
+ checkConcurrentModification(resource.version, version, identifier);
1092
+ updatedResource.version += 1;
1189
1093
  }
1190
- updateFunc(context, modifiedResource, action);
1191
1094
  });
1192
- if (!(0, import_deep_equal.default)(modifiedResource, resource)) {
1193
- this.save(context, modifiedResource);
1095
+ if (resource.version != updatedResource.version) {
1096
+ this.saveUpdate(context, version, updatedResource);
1194
1097
  }
1195
- const result = this.postProcessResource(modifiedResource);
1098
+ const result = this.postProcessResource(updatedResource);
1196
1099
  if (!result) {
1197
1100
  throw new Error("invalid post process action");
1198
1101
  }
1199
1102
  return result;
1200
1103
  }
1201
- postProcessResource(resource) {
1202
- return resource;
1203
- }
1204
1104
  };
1205
1105
  var AbstractResourceRepository = class extends AbstractRepository {
1206
1106
  constructor(storage) {
1207
1107
  super(storage);
1208
- this._storage.assertStorage(this.getTypeId());
1209
1108
  }
1210
- query(context, params = {}) {
1211
- const result = this._storage.query(context.projectKey, this.getTypeId(), {
1109
+ postProcessResource(resource) {
1110
+ return resource;
1111
+ }
1112
+ query(context, params = {}) {
1113
+ const result = this._storage.query(context.projectKey, this.getTypeId(), {
1212
1114
  expand: params.expand,
1213
1115
  where: params.where,
1214
1116
  offset: params.offset,
@@ -1218,8 +1120,13 @@ var AbstractResourceRepository = class extends AbstractRepository {
1218
1120
  return result;
1219
1121
  }
1220
1122
  get(context, id, params = {}) {
1221
- const resource = this._storage.get(context.projectKey, this.getTypeId(), id, params);
1222
- return this.postProcessResource(resource);
1123
+ const resource = this._storage.get(
1124
+ context.projectKey,
1125
+ this.getTypeId(),
1126
+ id,
1127
+ params
1128
+ );
1129
+ return resource ? this.postProcessResource(resource) : null;
1223
1130
  }
1224
1131
  getByKey(context, key, params = {}) {
1225
1132
  const resource = this._storage.getByKey(
@@ -1228,7 +1135,7 @@ var AbstractResourceRepository = class extends AbstractRepository {
1228
1135
  key,
1229
1136
  params
1230
1137
  );
1231
- return this.postProcessResource(resource);
1138
+ return resource ? this.postProcessResource(resource) : null;
1232
1139
  }
1233
1140
  delete(context, id, params = {}) {
1234
1141
  const resource = this._storage.delete(
@@ -1237,122 +1144,38 @@ var AbstractResourceRepository = class extends AbstractRepository {
1237
1144
  id,
1238
1145
  params
1239
1146
  );
1240
- return this.postProcessResource(resource);
1147
+ return resource ? this.postProcessResource(resource) : null;
1241
1148
  }
1242
- save(context, resource) {
1243
- const current = this.get(context, resource.id);
1244
- if (current) {
1245
- checkConcurrentModification(current, resource.version);
1246
- } else {
1247
- if (resource.version !== 0) {
1248
- throw new CommercetoolsError(
1249
- {
1250
- code: "InvalidOperation",
1251
- message: "version on create must be 0"
1252
- },
1253
- 400
1254
- );
1255
- }
1256
- }
1257
- resource.version += 1;
1149
+ saveNew(context, resource) {
1150
+ resource.version = 1;
1258
1151
  this._storage.add(context.projectKey, this.getTypeId(), resource);
1259
1152
  }
1260
- };
1261
-
1262
- // src/repositories/cart-discount.ts
1263
- var CartDiscountRepository = class extends AbstractResourceRepository {
1264
- constructor() {
1265
- super(...arguments);
1266
- this.actions = {
1267
- setKey: (context, resource, { key }) => {
1268
- resource.key = key;
1269
- },
1270
- setDescription: (context, resource, { description }) => {
1271
- resource.description = description;
1272
- },
1273
- setValidFrom: (context, resource, { validFrom }) => {
1274
- resource.validFrom = validFrom;
1275
- },
1276
- setValidUntil: (context, resource, { validUntil }) => {
1277
- resource.validUntil = validUntil;
1278
- },
1279
- setValidFromAndUntil: (context, resource, { validFrom, validUntil }) => {
1280
- resource.validFrom = validFrom;
1281
- resource.validUntil = validUntil;
1282
- },
1283
- changeSortOrder: (context, resource, { sortOrder }) => {
1284
- resource.sortOrder = sortOrder;
1285
- },
1286
- changeIsActive: (context, resource, { isActive }) => {
1287
- resource.isActive = isActive;
1288
- }
1289
- };
1290
- }
1291
- getTypeId() {
1292
- return "cart-discount";
1293
- }
1294
- create(context, draft) {
1295
- const resource = {
1296
- ...getBaseResourceProperties(),
1297
- key: draft.key,
1298
- description: draft.description,
1299
- cartPredicate: draft.cartPredicate,
1300
- isActive: draft.isActive || false,
1301
- name: draft.name,
1302
- references: [],
1303
- target: draft.target,
1304
- requiresDiscountCode: draft.requiresDiscountCode || false,
1305
- sortOrder: draft.sortOrder,
1306
- stackingMode: draft.stackingMode || "Stacking",
1307
- validFrom: draft.validFrom,
1308
- validUntil: draft.validUntil,
1309
- value: this.transformValueDraft(draft.value)
1310
- };
1311
- this.save(context, resource);
1312
- return resource;
1313
- }
1314
- transformValueDraft(value) {
1315
- switch (value.type) {
1316
- case "absolute": {
1317
- return {
1318
- type: "absolute",
1319
- money: value.money.map(createTypedMoney)
1320
- };
1321
- }
1322
- case "fixed": {
1323
- return {
1324
- type: "fixed",
1325
- money: value.money.map(createTypedMoney)
1326
- };
1327
- }
1328
- case "giftLineItem": {
1329
- return {
1330
- ...value
1331
- };
1332
- }
1333
- case "relative": {
1334
- return {
1335
- ...value
1336
- };
1337
- }
1153
+ saveUpdate(context, version, resource) {
1154
+ const current = this._storage.get(
1155
+ context.projectKey,
1156
+ this.getTypeId(),
1157
+ resource.id
1158
+ );
1159
+ if (!current) {
1160
+ throw new CommercetoolsError(
1161
+ {
1162
+ code: "ResourceNotFound",
1163
+ message: "Resource not found while updating"
1164
+ },
1165
+ 400
1166
+ );
1338
1167
  }
1339
- return value;
1340
- }
1341
- };
1342
-
1343
- // src/services/cart-discount.ts
1344
- var CartDiscountService = class extends AbstractService {
1345
- constructor(parent, storage) {
1346
- super(parent);
1347
- this.repository = new CartDiscountRepository(storage);
1348
- }
1349
- getBasePath() {
1350
- return "cart-discounts";
1168
+ checkConcurrentModification(current.version, version, resource.id);
1169
+ if (current.version === resource.version) {
1170
+ throw new Error("Internal error: no changes to save");
1171
+ }
1172
+ resource.lastModifiedAt = new Date().toISOString();
1173
+ this._storage.add(context.projectKey, this.getTypeId(), resource);
1174
+ return resource;
1351
1175
  }
1352
1176
  };
1353
1177
 
1354
1178
  // src/repositories/cart.ts
1355
- var import_uuid3 = require("uuid");
1356
1179
  var CartRepository = class extends AbstractResourceRepository {
1357
1180
  constructor() {
1358
1181
  super(...arguments);
@@ -1360,7 +1183,6 @@ var CartRepository = class extends AbstractResourceRepository {
1360
1183
  addLineItem: (context, resource, { productId, variantId, sku, quantity = 1 }) => {
1361
1184
  var _a;
1362
1185
  let product = null;
1363
- let variant;
1364
1186
  if (productId && variantId) {
1365
1187
  product = this._storage.get(
1366
1188
  context.projectKey,
@@ -1384,7 +1206,7 @@ var CartRepository = class extends AbstractResourceRepository {
1384
1206
  message: sku ? `A product containing a variant with SKU '${sku}' not found.` : `A product with ID '${productId}' not found.`
1385
1207
  });
1386
1208
  }
1387
- variant = [
1209
+ const variant = [
1388
1210
  product.masterData.current.masterVariant,
1389
1211
  ...product.masterData.current.variants
1390
1212
  ].find((x) => {
@@ -1433,11 +1255,13 @@ var CartRepository = class extends AbstractResourceRepository {
1433
1255
  id: (0, import_uuid3.v4)(),
1434
1256
  productId: product.id,
1435
1257
  productKey: product.key,
1436
- name: product.masterData.current.name,
1437
1258
  productSlug: product.masterData.current.slug,
1438
1259
  productType: product.productType,
1260
+ name: product.masterData.current.name,
1439
1261
  variant,
1440
1262
  price,
1263
+ taxedPricePortions: [],
1264
+ perMethodTaxRate: [],
1441
1265
  totalPrice: {
1442
1266
  ...price.value,
1443
1267
  centAmount: price.value.centAmount * quantity
@@ -1461,7 +1285,9 @@ var CartRepository = class extends AbstractResourceRepository {
1461
1285
  }
1462
1286
  const shouldDelete = !quantity || quantity >= lineItem.quantity;
1463
1287
  if (shouldDelete) {
1464
- resource.lineItems = resource.lineItems.filter((x) => x.id !== lineItemId);
1288
+ resource.lineItems = resource.lineItems.filter(
1289
+ (x) => x.id !== lineItemId
1290
+ );
1465
1291
  } else {
1466
1292
  resource.lineItems.map((x) => {
1467
1293
  if (x.id === lineItemId && quantity) {
@@ -1477,19 +1303,24 @@ var CartRepository = class extends AbstractResourceRepository {
1477
1303
  resource.billingAddress = address;
1478
1304
  },
1479
1305
  setShippingMethod: (context, resource, { shippingMethod }) => {
1480
- const resolvedType = this._storage.getByResourceIdentifier(
1481
- context.projectKey,
1482
- shippingMethod
1483
- );
1484
- if (!resolvedType) {
1485
- throw new Error(`Type ${shippingMethod} not found`);
1486
- }
1487
- resource.shippingInfo = {
1488
- shippingMethod: {
1489
- typeId: "shipping-method",
1490
- id: resolvedType.id
1306
+ if (shippingMethod) {
1307
+ const method = this._storage.getByResourceIdentifier(
1308
+ context.projectKey,
1309
+ shippingMethod
1310
+ );
1311
+ if (!method) {
1312
+ throw new Error(`Type ${shippingMethod} not found`);
1491
1313
  }
1492
- };
1314
+ resource.shippingInfo = {
1315
+ shippingMethod: {
1316
+ typeId: "shipping-method",
1317
+ id: method.id
1318
+ },
1319
+ shippingMethodName: method.name
1320
+ };
1321
+ } else {
1322
+ resource.shippingInfo = void 0;
1323
+ }
1493
1324
  },
1494
1325
  setCountry: (context, resource, { country }) => {
1495
1326
  resource.country = country;
@@ -1533,7 +1364,6 @@ var CartRepository = class extends AbstractResourceRepository {
1533
1364
  this.draftLineItemtoLineItem = (projectKey, draftLineItem, currency, country) => {
1534
1365
  const { productId, quantity, variantId, sku } = draftLineItem;
1535
1366
  let product = null;
1536
- let variant;
1537
1367
  if (productId && variantId) {
1538
1368
  product = this._storage.get(projectKey, "product", productId, {});
1539
1369
  } else if (sku) {
@@ -1552,7 +1382,7 @@ var CartRepository = class extends AbstractResourceRepository {
1552
1382
  message: sku ? `A product containing a variant with SKU '${sku}' not found.` : `A product with ID '${productId}' not found.`
1553
1383
  });
1554
1384
  }
1555
- variant = [
1385
+ const variant = [
1556
1386
  product.masterData.current.masterVariant,
1557
1387
  ...product.masterData.current.variants
1558
1388
  ].find((x) => {
@@ -1578,15 +1408,17 @@ var CartRepository = class extends AbstractResourceRepository {
1578
1408
  id: (0, import_uuid3.v4)(),
1579
1409
  productId: product.id,
1580
1410
  productKey: product.key,
1581
- name: product.masterData.current.name,
1582
1411
  productSlug: product.masterData.current.slug,
1583
1412
  productType: product.productType,
1413
+ name: product.masterData.current.name,
1584
1414
  variant,
1585
1415
  price,
1586
1416
  totalPrice: {
1587
1417
  ...price.value,
1588
1418
  centAmount: price.value.centAmount * quant
1589
1419
  },
1420
+ taxedPricePortions: [],
1421
+ perMethodTaxRate: [],
1590
1422
  quantity: quant,
1591
1423
  discountedPricePerQuantity: [],
1592
1424
  lineItemMode: "Standard",
@@ -1611,21 +1443,23 @@ var CartRepository = class extends AbstractResourceRepository {
1611
1443
  const resource = {
1612
1444
  ...getBaseResourceProperties(),
1613
1445
  cartState: "Active",
1614
- lineItems,
1446
+ country: draft.country,
1615
1447
  customLineItems: [],
1448
+ lineItems,
1449
+ locale: draft.locale,
1450
+ taxCalculationMode: draft.taxCalculationMode ?? "LineItemLevel",
1451
+ taxMode: draft.taxMode ?? "Platform",
1452
+ taxRoundingMode: draft.taxRoundingMode ?? "HalfEven",
1616
1453
  totalPrice: {
1617
1454
  type: "centPrecision",
1618
1455
  centAmount: 0,
1619
1456
  currencyCode: draft.currency,
1620
1457
  fractionDigits: 0
1621
1458
  },
1622
- taxMode: draft.taxMode ?? "Platform",
1623
- taxRoundingMode: draft.taxRoundingMode ?? "HalfEven",
1624
- taxCalculationMode: draft.taxCalculationMode ?? "LineItemLevel",
1625
- refusedGifts: [],
1626
- locale: draft.locale,
1627
- country: draft.country,
1459
+ shippingMode: "Single",
1460
+ shipping: [],
1628
1461
  origin: draft.origin ?? "Customer",
1462
+ refusedGifts: [],
1629
1463
  custom: createCustomFields(
1630
1464
  draft.custom,
1631
1465
  context.projectKey,
@@ -1633,7 +1467,7 @@ var CartRepository = class extends AbstractResourceRepository {
1633
1467
  )
1634
1468
  };
1635
1469
  resource.totalPrice.centAmount = calculateCartTotalPrice(resource);
1636
- this.save(context, resource);
1470
+ this.saveNew(context, resource);
1637
1471
  return resource;
1638
1472
  }
1639
1473
  getActiveCart(projectKey) {
@@ -1663,313 +1497,84 @@ var selectPrice = ({
1663
1497
  var calculateLineItemTotalPrice = (lineItem) => lineItem.price.value.centAmount * lineItem.quantity;
1664
1498
  var calculateCartTotalPrice = (cart) => cart.lineItems.reduce((cur, item) => cur + item.totalPrice.centAmount, 0);
1665
1499
 
1666
- // src/repositories/order.ts
1667
- var import_assert2 = __toESM(require("assert"));
1668
- var OrderRepository = class extends AbstractResourceRepository {
1500
+ // src/repositories/cart-discount.ts
1501
+ var CartDiscountRepository = class extends AbstractResourceRepository {
1669
1502
  constructor() {
1670
1503
  super(...arguments);
1671
1504
  this.actions = {
1672
- addPayment: (context, resource, { payment }) => {
1673
- const resolvedPayment = this._storage.getByResourceIdentifier(
1674
- context.projectKey,
1675
- payment
1676
- );
1677
- if (!resolvedPayment) {
1678
- throw new Error(`Payment ${payment.id} not found`);
1679
- }
1680
- if (!resource.paymentInfo) {
1681
- resource.paymentInfo = {
1682
- payments: []
1683
- };
1684
- }
1685
- resource.paymentInfo.payments.push({
1686
- typeId: "payment",
1687
- id: payment.id
1688
- });
1689
- },
1690
- changeOrderState: (context, resource, { orderState }) => {
1691
- resource.orderState = orderState;
1692
- },
1693
- changePaymentState: (context, resource, { paymentState }) => {
1694
- resource.paymentState = paymentState;
1695
- },
1696
- transitionState: (context, resource, { state }) => {
1697
- const resolvedType = this._storage.getByResourceIdentifier(
1698
- context.projectKey,
1699
- state
1700
- );
1701
- if (!resolvedType) {
1702
- throw new Error(
1703
- `No state found with key=${state.key} or id=${state.key}`
1704
- );
1705
- }
1706
- resource.state = { typeId: "state", id: resolvedType.id };
1707
- },
1708
- setBillingAddress: (context, resource, { address }) => {
1709
- resource.billingAddress = address;
1710
- },
1711
- setCustomerEmail: (context, resource, { email }) => {
1712
- resource.customerEmail = email;
1505
+ setKey: (context, resource, { key }) => {
1506
+ resource.key = key;
1713
1507
  },
1714
- setCustomField: (context, resource, { name, value }) => {
1715
- if (!resource.custom) {
1716
- throw new Error("Resource has no custom field");
1717
- }
1718
- resource.custom.fields[name] = value;
1508
+ setDescription: (context, resource, { description }) => {
1509
+ resource.description = description;
1719
1510
  },
1720
- setCustomType: (context, resource, { type, fields }) => {
1721
- if (!type) {
1722
- resource.custom = void 0;
1723
- } else {
1724
- const resolvedType = this._storage.getByResourceIdentifier(
1725
- context.projectKey,
1726
- type
1727
- );
1728
- if (!resolvedType) {
1729
- throw new Error(`Type ${type} not found`);
1730
- }
1731
- resource.custom = {
1732
- type: {
1733
- typeId: "type",
1734
- id: resolvedType.id
1735
- },
1736
- fields: fields || []
1737
- };
1738
- }
1511
+ setValidFrom: (context, resource, { validFrom }) => {
1512
+ resource.validFrom = validFrom;
1739
1513
  },
1740
- setLocale: (context, resource, { locale }) => {
1741
- resource.locale = locale;
1514
+ setValidUntil: (context, resource, { validUntil }) => {
1515
+ resource.validUntil = validUntil;
1742
1516
  },
1743
- setOrderNumber: (context, resource, { orderNumber }) => {
1744
- resource.orderNumber = orderNumber;
1517
+ setValidFromAndUntil: (context, resource, { validFrom, validUntil }) => {
1518
+ resource.validFrom = validFrom;
1519
+ resource.validUntil = validUntil;
1745
1520
  },
1746
- setShippingAddress: (context, resource, { address }) => {
1747
- resource.shippingAddress = address;
1521
+ changeSortOrder: (context, resource, { sortOrder }) => {
1522
+ resource.sortOrder = sortOrder;
1748
1523
  },
1749
- setStore: (context, resource, { store }) => {
1750
- if (!store)
1751
- return;
1752
- const resolvedType = this._storage.getByResourceIdentifier(
1753
- context.projectKey,
1754
- store
1755
- );
1756
- if (!resolvedType) {
1757
- throw new Error(`No store found with key=${store.key}`);
1758
- }
1759
- const storeReference = resolvedType;
1760
- resource.store = {
1761
- typeId: "store",
1762
- key: storeReference.key
1763
- };
1524
+ changeIsActive: (context, resource, { isActive }) => {
1525
+ resource.isActive = isActive;
1764
1526
  }
1765
1527
  };
1766
1528
  }
1767
1529
  getTypeId() {
1768
- return "order";
1530
+ return "cart-discount";
1769
1531
  }
1770
1532
  create(context, draft) {
1771
- (0, import_assert2.default)(draft.cart, "draft.cart is missing");
1772
- return this.createFromCart(
1773
- context,
1774
- {
1775
- id: draft.cart.id,
1776
- typeId: "cart"
1777
- },
1778
- draft.orderNumber
1779
- );
1780
- }
1781
- createFromCart(context, cartReference, orderNumber) {
1782
- const cart = this._storage.getByResourceIdentifier(
1783
- context.projectKey,
1784
- cartReference
1785
- );
1786
- if (!cart) {
1787
- throw new Error("Cannot find cart");
1788
- }
1789
- const resource = {
1790
- ...getBaseResourceProperties(),
1791
- orderNumber,
1792
- cart: cartReference,
1793
- orderState: "Open",
1794
- lineItems: [],
1795
- customLineItems: [],
1796
- totalPrice: cart.totalPrice,
1797
- refusedGifts: [],
1798
- origin: "Customer",
1799
- syncInfo: [],
1800
- store: context.storeKey ? {
1801
- key: context.storeKey,
1802
- typeId: "store"
1803
- } : void 0,
1804
- lastMessageSequenceNumber: 0
1805
- };
1806
- this.save(context, resource);
1807
- return resource;
1808
- }
1809
- import(context, draft) {
1810
- var _a, _b;
1811
- (0, import_assert2.default)(this, "OrderRepository not valid");
1812
1533
  const resource = {
1813
1534
  ...getBaseResourceProperties(),
1814
- billingAddress: draft.billingAddress,
1815
- shippingAddress: draft.shippingAddress,
1816
- custom: createCustomFields(
1817
- draft.custom,
1818
- context.projectKey,
1819
- this._storage
1820
- ),
1821
- customerEmail: draft.customerEmail,
1822
- lastMessageSequenceNumber: 0,
1823
- orderNumber: draft.orderNumber,
1824
- orderState: draft.orderState || "Open",
1825
- origin: draft.origin || "Customer",
1826
- paymentState: draft.paymentState,
1827
- refusedGifts: [],
1828
- store: resolveStoreReference(
1829
- draft.store,
1830
- context.projectKey,
1831
- this._storage
1832
- ),
1833
- syncInfo: [],
1834
- lineItems: ((_a = draft.lineItems) == null ? void 0 : _a.map(
1835
- (item) => this.lineItemFromImportDraft.bind(this)(context, item)
1836
- )) || [],
1837
- customLineItems: ((_b = draft.customLineItems) == null ? void 0 : _b.map(
1838
- (item) => this.customLineItemFromImportDraft.bind(this)(context, item)
1839
- )) || [],
1840
- totalPrice: {
1841
- type: "centPrecision",
1842
- ...draft.totalPrice,
1843
- fractionDigits: 2
1844
- }
1535
+ key: draft.key,
1536
+ description: draft.description,
1537
+ cartPredicate: draft.cartPredicate,
1538
+ isActive: draft.isActive || false,
1539
+ name: draft.name,
1540
+ references: [],
1541
+ target: draft.target,
1542
+ requiresDiscountCode: draft.requiresDiscountCode || false,
1543
+ sortOrder: draft.sortOrder,
1544
+ stackingMode: draft.stackingMode || "Stacking",
1545
+ validFrom: draft.validFrom,
1546
+ validUntil: draft.validUntil,
1547
+ value: this.transformValueDraft(draft.value)
1845
1548
  };
1846
- this.save(context, resource);
1549
+ this.saveNew(context, resource);
1847
1550
  return resource;
1848
1551
  }
1849
- lineItemFromImportDraft(context, draft) {
1850
- let product;
1851
- let variant;
1852
- if (draft.variant.sku) {
1853
- variant = {
1854
- id: 0,
1855
- sku: draft.variant.sku
1856
- };
1857
- var items = this._storage.query(context.projectKey, "product", {
1858
- where: [
1859
- `masterData(current(masterVariant(sku="${draft.variant.sku}"))) or masterData(current(variants(sku="${draft.variant.sku}")))`
1860
- ]
1861
- });
1862
- if (items.count !== 1) {
1863
- throw new CommercetoolsError({
1864
- code: "General",
1865
- message: `A product containing a variant with SKU '${draft.variant.sku}' not found.`
1866
- });
1552
+ transformValueDraft(value) {
1553
+ switch (value.type) {
1554
+ case "absolute": {
1555
+ return {
1556
+ type: "absolute",
1557
+ money: value.money.map(createTypedMoney)
1558
+ };
1867
1559
  }
1868
- product = items.results[0];
1869
- if (product.masterData.current.masterVariant.sku === draft.variant.sku) {
1870
- variant = product.masterData.current.masterVariant;
1871
- } else {
1872
- variant = product.masterData.current.variants.find(
1873
- (v) => v.sku === draft.variant.sku
1874
- );
1560
+ case "fixed": {
1561
+ return {
1562
+ type: "fixed",
1563
+ money: value.money.map(createTypedMoney)
1564
+ };
1875
1565
  }
1876
- if (!variant) {
1877
- throw new Error("Internal state error");
1566
+ case "giftLineItem": {
1567
+ return {
1568
+ ...value
1569
+ };
1878
1570
  }
1879
- } else {
1880
- throw new Error("No product found");
1881
- }
1882
- const lineItem = {
1883
- ...getBaseResourceProperties(),
1884
- custom: createCustomFields(
1885
- draft.custom,
1886
- context.projectKey,
1887
- this._storage
1888
- ),
1889
- discountedPricePerQuantity: [],
1890
- lineItemMode: "Standard",
1891
- name: draft.name,
1892
- price: createPrice(draft.price),
1893
- priceMode: "Platform",
1894
- productId: product.id,
1895
- productType: product.productType,
1896
- quantity: draft.quantity,
1897
- state: draft.state || [],
1898
- taxRate: draft.taxRate,
1899
- totalPrice: createTypedMoney(draft.price.value),
1900
- variant: {
1901
- id: variant.id,
1902
- sku: variant.sku,
1903
- price: createPrice(draft.price)
1571
+ case "relative": {
1572
+ return {
1573
+ ...value
1574
+ };
1904
1575
  }
1905
- };
1906
- return lineItem;
1907
- }
1908
- customLineItemFromImportDraft(context, draft) {
1909
- const lineItem = {
1910
- ...getBaseResourceProperties(),
1911
- custom: createCustomFields(
1912
- draft.custom,
1913
- context.projectKey,
1914
- this._storage
1915
- ),
1916
- discountedPricePerQuantity: [],
1917
- money: createTypedMoney(draft.money),
1918
- name: draft.name,
1919
- quantity: draft.quantity,
1920
- slug: draft.slug,
1921
- state: [],
1922
- totalPrice: createTypedMoney(draft.money)
1923
- };
1924
- return lineItem;
1925
- }
1926
- getWithOrderNumber(context, orderNumber, params = {}) {
1927
- const result = this._storage.query(context.projectKey, this.getTypeId(), {
1928
- ...params,
1929
- where: [`orderNumber="${orderNumber}"`]
1930
- });
1931
- if (result.count === 1) {
1932
- return result.results[0];
1933
1576
  }
1934
- if (result.count > 1) {
1935
- throw new Error("Duplicate order numbers");
1936
- }
1937
- return;
1938
- }
1939
- };
1940
-
1941
- // src/services/cart.ts
1942
- var CartService = class extends AbstractService {
1943
- constructor(parent, storage) {
1944
- super(parent);
1945
- this.repository = new CartRepository(storage);
1946
- this.orderRepository = new OrderRepository(storage);
1947
- }
1948
- getBasePath() {
1949
- return "carts";
1950
- }
1951
- extraRoutes(parent) {
1952
- parent.post("/replicate", (request, response) => {
1953
- const context = getRepositoryContext(request);
1954
- const cartOrOrder = request.body.reference.typeId === "order" ? this.orderRepository.get(context, request.body.reference.id) : this.repository.get(context, request.body.reference.id);
1955
- if (!cartOrOrder) {
1956
- return response.status(400).send();
1957
- }
1958
- const cartDraft = {
1959
- ...cartOrOrder,
1960
- currency: cartOrOrder.totalPrice.currencyCode,
1961
- discountCodes: [],
1962
- lineItems: cartOrOrder.lineItems.map((lineItem) => {
1963
- return {
1964
- ...lineItem,
1965
- variantId: lineItem.variant.id,
1966
- sku: lineItem.variant.sku
1967
- };
1968
- })
1969
- };
1970
- const newCart = this.repository.create(context, cartDraft);
1971
- return response.status(200).send(newCart);
1972
- });
1577
+ return value;
1973
1578
  }
1974
1579
  };
1975
1580
 
@@ -2067,43 +1672,30 @@ var CategoryRepository = class extends AbstractResourceRepository {
2067
1672
  externalId: draft.externalId || "",
2068
1673
  parent: draft.parent ? { typeId: "category", id: draft.parent.id } : void 0,
2069
1674
  ancestors: [],
2070
- assets: ((_a = draft.assets) == null ? void 0 : _a.map((d) => {
2071
- return {
2072
- id: (0, import_uuid4.v4)(),
2073
- name: d.name,
2074
- description: d.description,
2075
- sources: d.sources,
2076
- tags: d.tags,
2077
- key: d.key,
2078
- custom: createCustomFields(
2079
- draft.custom,
2080
- context.projectKey,
2081
- this._storage
2082
- )
2083
- };
2084
- })) || [],
1675
+ assets: ((_a = draft.assets) == null ? void 0 : _a.map((d) => ({
1676
+ id: (0, import_uuid4.v4)(),
1677
+ name: d.name,
1678
+ description: d.description,
1679
+ sources: d.sources,
1680
+ tags: d.tags,
1681
+ key: d.key,
1682
+ custom: createCustomFields(
1683
+ draft.custom,
1684
+ context.projectKey,
1685
+ this._storage
1686
+ )
1687
+ }))) || [],
2085
1688
  custom: createCustomFields(
2086
1689
  draft.custom,
2087
1690
  context.projectKey,
2088
1691
  this._storage
2089
1692
  )
2090
1693
  };
2091
- this.save(context, resource);
1694
+ this.saveNew(context, resource);
2092
1695
  return resource;
2093
1696
  }
2094
1697
  };
2095
1698
 
2096
- // src/services/category.ts
2097
- var CategoryServices = class extends AbstractService {
2098
- constructor(parent, storage) {
2099
- super(parent);
2100
- this.repository = new CategoryRepository(storage);
2101
- }
2102
- getBasePath() {
2103
- return "categories";
2104
- }
2105
- };
2106
-
2107
1699
  // src/repositories/channel.ts
2108
1700
  var ChannelRepository = class extends AbstractResourceRepository {
2109
1701
  constructor() {
@@ -2169,83 +1761,62 @@ var ChannelRepository = class extends AbstractResourceRepository {
2169
1761
  this._storage
2170
1762
  )
2171
1763
  };
2172
- this.save(context, resource);
1764
+ this.saveNew(context, resource);
2173
1765
  return resource;
2174
1766
  }
2175
1767
  };
2176
1768
 
2177
- // src/services/channel.ts
2178
- var ChannelService = class extends AbstractService {
2179
- constructor(parent, storage) {
2180
- super(parent);
2181
- this.repository = new ChannelRepository(storage);
2182
- }
2183
- getBasePath() {
2184
- return "channels";
2185
- }
2186
- };
2187
-
2188
- // src/repositories/customer-group.ts
2189
- var CustomerGroupRepository = class extends AbstractResourceRepository {
2190
- constructor() {
2191
- super(...arguments);
2192
- this.actions = {
2193
- setKey: (context, resource, { key }) => {
2194
- resource.key = key;
2195
- },
2196
- changeName: (context, resource, { name }) => {
2197
- resource.name = name;
2198
- },
2199
- setCustomType: (context, resource, { type, fields }) => {
2200
- if (type) {
2201
- resource.custom = createCustomFields(
2202
- { type, fields },
2203
- context.projectKey,
2204
- this._storage
2205
- );
2206
- } else {
2207
- resource.custom = void 0;
2208
- }
2209
- },
2210
- setCustomField: (context, resource, { name, value }) => {
2211
- if (!resource.custom) {
2212
- return;
2213
- }
2214
- if (value === null) {
2215
- delete resource.custom.fields[name];
2216
- } else {
2217
- resource.custom.fields[name] = value;
2218
- }
2219
- }
2220
- };
2221
- }
2222
- getTypeId() {
2223
- return "customer";
1769
+ // src/repositories/custom-object.ts
1770
+ var CustomObjectRepository = class extends AbstractResourceRepository {
1771
+ getTypeId() {
1772
+ return "key-value-document";
2224
1773
  }
2225
1774
  create(context, draft) {
2226
- const resource = {
2227
- ...getBaseResourceProperties(),
2228
- key: draft.key,
2229
- name: draft.groupName,
2230
- custom: createCustomFields(
2231
- draft.custom,
2232
- context.projectKey,
2233
- this._storage
2234
- )
2235
- };
2236
- this.save(context, resource);
2237
- return resource;
2238
- }
2239
- };
2240
-
2241
- // src/services/customer-group.ts
2242
- var CustomerGroupService = class extends AbstractService {
2243
- constructor(parent, storage) {
2244
- super(parent);
2245
- this.repository = new CustomerGroupRepository(storage);
1775
+ const current = this.getWithContainerAndKey(
1776
+ context,
1777
+ draft.container,
1778
+ draft.key
1779
+ );
1780
+ if (current) {
1781
+ if (draft.version) {
1782
+ checkConcurrentModification(current.version, draft.version, current.id);
1783
+ } else {
1784
+ draft.version = current.version;
1785
+ }
1786
+ if (draft.value !== current.value) {
1787
+ const updated = cloneObject(current);
1788
+ updated.value = draft.value;
1789
+ updated.version += 1;
1790
+ this.saveUpdate(context, draft.version, updated);
1791
+ return updated;
1792
+ }
1793
+ return current;
1794
+ } else {
1795
+ if (draft.version) {
1796
+ throw new CommercetoolsError(
1797
+ {
1798
+ code: "InvalidOperation",
1799
+ message: "version on create must be 0"
1800
+ },
1801
+ 400
1802
+ );
1803
+ }
1804
+ const baseProperties = getBaseResourceProperties();
1805
+ const resource = {
1806
+ ...baseProperties,
1807
+ container: draft.container,
1808
+ key: draft.key,
1809
+ value: draft.value
1810
+ };
1811
+ this.saveNew(context, resource);
1812
+ return resource;
1813
+ }
2246
1814
  }
2247
- getBasePath() {
2248
- return "customer-groups";
1815
+ getWithContainerAndKey(context, container, key) {
1816
+ const items = this._storage.all(context.projectKey, this.getTypeId());
1817
+ return items.find(
1818
+ (item) => item.container === container && item.key === key
1819
+ );
2249
1820
  }
2250
1821
  };
2251
1822
 
@@ -2256,6 +1827,34 @@ var CustomerRepository = class extends AbstractResourceRepository {
2256
1827
  this.actions = {
2257
1828
  changeEmail: (_context, resource, { email }) => {
2258
1829
  resource.email = email;
1830
+ },
1831
+ setAuthenticationMode: (_context, resource, { authMode, password }) => {
1832
+ if (resource.authenticationMode === authMode) {
1833
+ throw new CommercetoolsError(
1834
+ {
1835
+ code: "InvalidInput",
1836
+ message: `The customer is already using the '${resource.authenticationMode}' authentication mode.`
1837
+ },
1838
+ 400
1839
+ );
1840
+ }
1841
+ resource.authenticationMode = authMode;
1842
+ if (authMode === "ExternalAuth") {
1843
+ delete resource.password;
1844
+ return;
1845
+ }
1846
+ if (authMode === "Password") {
1847
+ resource.password = password ? Buffer.from(password).toString("base64") : void 0;
1848
+ return;
1849
+ }
1850
+ throw new CommercetoolsError(
1851
+ {
1852
+ code: "InvalidJsonInput",
1853
+ message: "Request body does not contain valid JSON.",
1854
+ detailedErrorMessage: `actions -> authMode: Invalid enum value: '${authMode}'. Expected one of: 'Password','ExternalAuth'`
1855
+ },
1856
+ 400
1857
+ );
2259
1858
  }
2260
1859
  };
2261
1860
  }
@@ -2270,7 +1869,7 @@ var CustomerRepository = class extends AbstractResourceRepository {
2270
1869
  isEmailVerified: draft.isEmailVerified || false,
2271
1870
  addresses: []
2272
1871
  };
2273
- this.save(context, resource);
1872
+ this.saveNew(context, resource);
2274
1873
  return resource;
2275
1874
  }
2276
1875
  getMe(context) {
@@ -2286,127 +1885,57 @@ var CustomerRepository = class extends AbstractResourceRepository {
2286
1885
  }
2287
1886
  };
2288
1887
 
2289
- // src/services/customer.ts
2290
- var import_uuid5 = require("uuid");
2291
- var CustomerService = class extends AbstractService {
2292
- constructor(parent, storage) {
2293
- super(parent);
2294
- this.repository = new CustomerRepository(storage);
2295
- }
2296
- getBasePath() {
2297
- return "customers";
2298
- }
2299
- extraRoutes(parent) {
2300
- parent.post("/password-token", (request, response) => {
2301
- const customer = this.repository.query(getRepositoryContext(request), {
2302
- where: [`email="${request.body.email}"`]
2303
- });
2304
- const ttlMinutes = request.params.ttlMinutes ? +request.params.ttlMinutes : 34560;
2305
- const { version, ...rest } = getBaseResourceProperties();
2306
- return response.status(200).send({
2307
- ...rest,
2308
- customerId: customer.results[0].id,
2309
- expiresAt: new Date(Date.now() + ttlMinutes * 60).toISOString(),
2310
- value: (0, import_uuid5.v4)()
2311
- });
2312
- });
1888
+ // src/repositories/customer-group.ts
1889
+ var CustomerGroupRepository = class extends AbstractResourceRepository {
1890
+ constructor() {
1891
+ super(...arguments);
1892
+ this.actions = {
1893
+ setKey: (context, resource, { key }) => {
1894
+ resource.key = key;
1895
+ },
1896
+ changeName: (context, resource, { name }) => {
1897
+ resource.name = name;
1898
+ },
1899
+ setCustomType: (context, resource, { type, fields }) => {
1900
+ if (type) {
1901
+ resource.custom = createCustomFields(
1902
+ { type, fields },
1903
+ context.projectKey,
1904
+ this._storage
1905
+ );
1906
+ } else {
1907
+ resource.custom = void 0;
1908
+ }
1909
+ },
1910
+ setCustomField: (context, resource, { name, value }) => {
1911
+ if (!resource.custom) {
1912
+ return;
1913
+ }
1914
+ if (value === null) {
1915
+ delete resource.custom.fields[name];
1916
+ } else {
1917
+ resource.custom.fields[name] = value;
1918
+ }
1919
+ }
1920
+ };
2313
1921
  }
2314
- };
2315
-
2316
- // src/repositories/custom-object.ts
2317
- var CustomObjectRepository = class extends AbstractResourceRepository {
2318
1922
  getTypeId() {
2319
- return "key-value-document";
1923
+ return "customer-group";
2320
1924
  }
2321
1925
  create(context, draft) {
2322
- const current = this.getWithContainerAndKey(
2323
- context,
2324
- draft.container,
2325
- draft.key
2326
- );
2327
- const baseProperties = getBaseResourceProperties();
2328
- if (current) {
2329
- baseProperties.id = current.id;
2330
- if (!draft.version) {
2331
- draft.version = current.version;
2332
- }
2333
- checkConcurrentModification(current, draft.version);
2334
- if (draft.value === current.value) {
2335
- return current;
2336
- }
2337
- baseProperties.version = current.version;
2338
- } else {
2339
- if (draft.version) {
2340
- baseProperties.version = draft.version;
2341
- }
2342
- }
2343
1926
  const resource = {
2344
- ...baseProperties,
2345
- container: draft.container,
1927
+ ...getBaseResourceProperties(),
2346
1928
  key: draft.key,
2347
- value: draft.value
1929
+ name: draft.groupName,
1930
+ custom: createCustomFields(
1931
+ draft.custom,
1932
+ context.projectKey,
1933
+ this._storage
1934
+ )
2348
1935
  };
2349
- this.save(context, resource);
1936
+ this.saveNew(context, resource);
2350
1937
  return resource;
2351
1938
  }
2352
- getWithContainerAndKey(context, container, key) {
2353
- const items = this._storage.all(
2354
- context.projectKey,
2355
- this.getTypeId()
2356
- );
2357
- return items.find((item) => item.container === container && item.key === key);
2358
- }
2359
- };
2360
-
2361
- // src/services/custom-object.ts
2362
- var CustomObjectService = class extends AbstractService {
2363
- constructor(parent, storage) {
2364
- super(parent);
2365
- this.repository = new CustomObjectRepository(storage);
2366
- }
2367
- getBasePath() {
2368
- return "custom-objects";
2369
- }
2370
- extraRoutes(router) {
2371
- router.get("/:container/:key", this.getWithContainerAndKey.bind(this));
2372
- router.post("/:container/:key", this.createWithContainerAndKey.bind(this));
2373
- router.delete("/:container/:key", this.deleteWithContainerAndKey.bind(this));
2374
- }
2375
- getWithContainerAndKey(request, response) {
2376
- const result = this.repository.getWithContainerAndKey(
2377
- getRepositoryContext(request),
2378
- request.params.container,
2379
- request.params.key
2380
- );
2381
- if (!result) {
2382
- return response.status(404).send("Not Found");
2383
- }
2384
- return response.status(200).send(result);
2385
- }
2386
- createWithContainerAndKey(request, response) {
2387
- const draft = {
2388
- ...request.body,
2389
- key: request.params.key,
2390
- container: request.params.container
2391
- };
2392
- const result = this.repository.create(getRepositoryContext(request), draft);
2393
- return response.status(200).send(result);
2394
- }
2395
- deleteWithContainerAndKey(request, response) {
2396
- const current = this.repository.getWithContainerAndKey(
2397
- getRepositoryContext(request),
2398
- request.params.container,
2399
- request.params.key
2400
- );
2401
- if (!current) {
2402
- return response.status(404).send("Not Found");
2403
- }
2404
- const result = this.repository.delete(
2405
- getRepositoryContext(request),
2406
- current.id
2407
- );
2408
- return response.status(200).send(result);
2409
- }
2410
1939
  };
2411
1940
 
2412
1941
  // src/repositories/discount-code.ts
@@ -2476,7 +2005,7 @@ var DiscountCodeRepository = class extends AbstractResourceRepository {
2476
2005
  };
2477
2006
  }
2478
2007
  getTypeId() {
2479
- return "cart-discount";
2008
+ return "discount-code";
2480
2009
  }
2481
2010
  create(context, draft) {
2482
2011
  const resource = {
@@ -2505,26 +2034,15 @@ var DiscountCodeRepository = class extends AbstractResourceRepository {
2505
2034
  this._storage
2506
2035
  )
2507
2036
  };
2508
- this.save(context, resource);
2037
+ this.saveNew(context, resource);
2509
2038
  return resource;
2510
2039
  }
2511
2040
  };
2512
2041
 
2513
- // src/services/discount-code.ts
2514
- var DiscountCodeService = class extends AbstractService {
2515
- constructor(parent, storage) {
2516
- super(parent);
2517
- this.repository = new DiscountCodeRepository(storage);
2518
- }
2519
- getBasePath() {
2520
- return "discount-codes";
2521
- }
2522
- };
2523
-
2524
2042
  // src/lib/masking.ts
2525
2043
  var maskSecretValue = (resource, path) => {
2526
2044
  const parts = path.split(".");
2527
- const clone = JSON.parse(JSON.stringify(resource));
2045
+ const clone = cloneObject(resource);
2528
2046
  let val = clone;
2529
2047
  const target = parts.pop();
2530
2048
  for (let i = 0; i < parts.length; i++) {
@@ -2565,16 +2083,14 @@ var ExtensionRepository = class extends AbstractResourceRepository {
2565
2083
  postProcessResource(resource) {
2566
2084
  var _a;
2567
2085
  if (resource) {
2568
- if (resource.destination.type === "HTTP" && ((_a = resource.destination.authentication) == null ? void 0 : _a.type) === "AuthorizationHeader") {
2086
+ const extension = resource;
2087
+ if (extension.destination.type === "HTTP" && ((_a = extension.destination.authentication) == null ? void 0 : _a.type) === "AuthorizationHeader") {
2569
2088
  return maskSecretValue(
2570
- resource,
2089
+ extension,
2571
2090
  "destination.authentication.headerValue"
2572
2091
  );
2573
- } else if (resource.destination.type == "AWSLambda") {
2574
- return maskSecretValue(
2575
- resource,
2576
- "destination.accessSecret"
2577
- );
2092
+ } else if (extension.destination.type == "AWSLambda") {
2093
+ return maskSecretValue(resource, "destination.accessSecret");
2578
2094
  }
2579
2095
  }
2580
2096
  return resource;
@@ -2587,22 +2103,11 @@ var ExtensionRepository = class extends AbstractResourceRepository {
2587
2103
  destination: draft.destination,
2588
2104
  triggers: draft.triggers
2589
2105
  };
2590
- this.save(context, resource);
2106
+ this.saveNew(context, resource);
2591
2107
  return resource;
2592
2108
  }
2593
2109
  };
2594
2110
 
2595
- // src/services/extension.ts
2596
- var ExtensionServices = class extends AbstractService {
2597
- constructor(parent, storage) {
2598
- super(parent);
2599
- this.repository = new ExtensionRepository(storage);
2600
- }
2601
- getBasePath() {
2602
- return "extensions";
2603
- }
2604
- };
2605
-
2606
2111
  // src/repositories/inventory-entry.ts
2607
2112
  var InventoryEntryRepository = class extends AbstractResourceRepository {
2608
2113
  constructor() {
@@ -2669,65 +2174,62 @@ var InventoryEntryRepository = class extends AbstractResourceRepository {
2669
2174
  this._storage
2670
2175
  )
2671
2176
  };
2672
- this.save(context, resource);
2177
+ this.saveNew(context, resource);
2673
2178
  return resource;
2674
2179
  }
2675
2180
  };
2676
2181
 
2677
- // src/services/inventory-entry.ts
2678
- var InventoryEntryService = class extends AbstractService {
2679
- constructor(parent, storage) {
2680
- super(parent);
2681
- this.repository = new InventoryEntryRepository(storage);
2682
- }
2683
- getBasePath() {
2684
- return "inventory";
2685
- }
2686
- };
2182
+ // src/repositories/my-order.ts
2183
+ var import_assert3 = __toESM(require("assert"));
2687
2184
 
2688
- // src/services/my-cart.ts
2689
- var import_express3 = require("express");
2690
- var MyCartService = class extends AbstractService {
2691
- constructor(parent, storage) {
2692
- super(parent);
2693
- this.repository = new CartRepository(storage);
2694
- }
2695
- getBasePath() {
2696
- return "me";
2697
- }
2698
- registerRoutes(parent) {
2699
- const basePath = this.getBasePath();
2700
- const router = (0, import_express3.Router)({ mergeParams: true });
2701
- this.extraRoutes(router);
2702
- router.get("/active-cart", this.activeCart.bind(this));
2703
- router.get("/carts/", this.get.bind(this));
2704
- router.get("/carts/:id", this.getWithId.bind(this));
2705
- router.delete("/carts/:id", this.deletewithId.bind(this));
2706
- router.post("/carts/", this.post.bind(this));
2707
- router.post("/carts/:id", this.postWithId.bind(this));
2708
- parent.use(`/${basePath}`, router);
2709
- }
2710
- activeCart(request, response) {
2711
- const resource = this.repository.getActiveCart(request.params.projectKey);
2712
- if (!resource) {
2713
- return response.status(404).send("Not found");
2714
- }
2715
- return response.status(200).send(resource);
2716
- }
2717
- };
2718
-
2719
- // src/repositories/payment.ts
2720
- var import_uuid6 = require("uuid");
2721
- var PaymentRepository = class extends AbstractResourceRepository {
2185
+ // src/repositories/order.ts
2186
+ var import_assert2 = __toESM(require("assert"));
2187
+ var OrderRepository = class extends AbstractResourceRepository {
2722
2188
  constructor() {
2723
2189
  super(...arguments);
2724
- this.transactionFromTransactionDraft = (draft, context) => ({
2725
- ...draft,
2726
- id: (0, import_uuid6.v4)(),
2727
- amount: createTypedMoney(draft.amount),
2728
- custom: createCustomFields(draft.custom, context.projectKey, this._storage)
2729
- });
2730
2190
  this.actions = {
2191
+ addPayment: (context, resource, { payment }) => {
2192
+ const resolvedPayment = this._storage.getByResourceIdentifier(
2193
+ context.projectKey,
2194
+ payment
2195
+ );
2196
+ if (!resolvedPayment) {
2197
+ throw new Error(`Payment ${payment.id} not found`);
2198
+ }
2199
+ if (!resource.paymentInfo) {
2200
+ resource.paymentInfo = {
2201
+ payments: []
2202
+ };
2203
+ }
2204
+ resource.paymentInfo.payments.push({
2205
+ typeId: "payment",
2206
+ id: payment.id
2207
+ });
2208
+ },
2209
+ changeOrderState: (context, resource, { orderState }) => {
2210
+ resource.orderState = orderState;
2211
+ },
2212
+ changePaymentState: (context, resource, { paymentState }) => {
2213
+ resource.paymentState = paymentState;
2214
+ },
2215
+ transitionState: (context, resource, { state }) => {
2216
+ const resolvedType = this._storage.getByResourceIdentifier(
2217
+ context.projectKey,
2218
+ state
2219
+ );
2220
+ if (!resolvedType) {
2221
+ throw new Error(
2222
+ `No state found with key=${state.key} or id=${state.key}`
2223
+ );
2224
+ }
2225
+ resource.state = { typeId: "state", id: resolvedType.id };
2226
+ },
2227
+ setBillingAddress: (context, resource, { address }) => {
2228
+ resource.billingAddress = address;
2229
+ },
2230
+ setCustomerEmail: (context, resource, { email }) => {
2231
+ resource.customerEmail = email;
2232
+ },
2731
2233
  setCustomField: (context, resource, { name, value }) => {
2732
2234
  if (!resource.custom) {
2733
2235
  throw new Error("Resource has no custom field");
@@ -2754,269 +2256,622 @@ var PaymentRepository = class extends AbstractResourceRepository {
2754
2256
  };
2755
2257
  }
2756
2258
  },
2757
- addTransaction: (context, resource, { transaction }) => {
2758
- resource.transactions = [
2759
- ...resource.transactions,
2760
- this.transactionFromTransactionDraft(transaction, context)
2761
- ];
2259
+ setLocale: (context, resource, { locale }) => {
2260
+ resource.locale = locale;
2762
2261
  },
2763
- changeTransactionState: (_context, resource, { transactionId, state }) => {
2764
- const index = resource.transactions.findIndex(
2765
- (e) => e.id === transactionId
2766
- );
2767
- const updatedTransaction = {
2768
- ...resource.transactions[index],
2769
- state
2770
- };
2771
- resource.transactions[index] = updatedTransaction;
2262
+ setOrderNumber: (context, resource, { orderNumber }) => {
2263
+ resource.orderNumber = orderNumber;
2772
2264
  },
2773
- transitionState: (context, resource, { state }) => {
2774
- const stateObj = this._storage.getByResourceIdentifier(
2265
+ setShippingAddress: (context, resource, { address }) => {
2266
+ resource.shippingAddress = address;
2267
+ },
2268
+ setStore: (context, resource, { store }) => {
2269
+ if (!store)
2270
+ return;
2271
+ const resolvedType = this._storage.getByResourceIdentifier(
2775
2272
  context.projectKey,
2776
- state
2273
+ store
2777
2274
  );
2778
- if (!stateObj) {
2779
- throw new Error(`State ${state} not found`);
2275
+ if (!resolvedType) {
2276
+ throw new Error(`No store found with key=${store.key}`);
2780
2277
  }
2781
- resource.paymentStatus.state = {
2782
- typeId: "state",
2783
- id: stateObj.id,
2784
- obj: stateObj
2278
+ const storeReference = resolvedType;
2279
+ resource.store = {
2280
+ typeId: "store",
2281
+ key: storeReference.key
2785
2282
  };
2786
2283
  }
2787
2284
  };
2788
2285
  }
2789
2286
  getTypeId() {
2790
- return "payment";
2287
+ return "order";
2791
2288
  }
2792
2289
  create(context, draft) {
2290
+ (0, import_assert2.default)(draft.cart, "draft.cart is missing");
2291
+ return this.createFromCart(
2292
+ context,
2293
+ {
2294
+ id: draft.cart.id,
2295
+ typeId: "cart"
2296
+ },
2297
+ draft.orderNumber
2298
+ );
2299
+ }
2300
+ createFromCart(context, cartReference, orderNumber) {
2301
+ const cart = this._storage.getByResourceIdentifier(
2302
+ context.projectKey,
2303
+ cartReference
2304
+ );
2305
+ if (!cart) {
2306
+ throw new Error("Cannot find cart");
2307
+ }
2793
2308
  const resource = {
2794
2309
  ...getBaseResourceProperties(),
2795
- amountPlanned: createTypedMoney(draft.amountPlanned),
2796
- paymentMethodInfo: draft.paymentMethodInfo,
2797
- paymentStatus: draft.paymentStatus ? {
2798
- ...draft.paymentStatus,
2799
- state: draft.paymentStatus.state ? getReferenceFromResourceIdentifier(
2800
- draft.paymentStatus.state,
2801
- context.projectKey,
2802
- this._storage
2803
- ) : void 0
2804
- } : {},
2805
- transactions: (draft.transactions || []).map(
2806
- (t) => this.transactionFromTransactionDraft(t, context)
2310
+ orderNumber,
2311
+ cart: cartReference,
2312
+ orderState: "Open",
2313
+ lineItems: [],
2314
+ customLineItems: [],
2315
+ totalPrice: cart.totalPrice,
2316
+ refusedGifts: [],
2317
+ origin: "Customer",
2318
+ syncInfo: [],
2319
+ shippingMode: cart.shippingMode,
2320
+ shipping: cart.shipping,
2321
+ store: context.storeKey ? {
2322
+ key: context.storeKey,
2323
+ typeId: "store"
2324
+ } : void 0,
2325
+ lastMessageSequenceNumber: 0
2326
+ };
2327
+ this.saveNew(context, resource);
2328
+ return resource;
2329
+ }
2330
+ import(context, draft) {
2331
+ var _a, _b;
2332
+ (0, import_assert2.default)(this, "OrderRepository not valid");
2333
+ const resource = {
2334
+ ...getBaseResourceProperties(),
2335
+ billingAddress: draft.billingAddress,
2336
+ shippingAddress: draft.shippingAddress,
2337
+ custom: createCustomFields(
2338
+ draft.custom,
2339
+ context.projectKey,
2340
+ this._storage
2807
2341
  ),
2808
- interfaceInteractions: (draft.interfaceInteractions || []).map(
2809
- (interaction) => createCustomFields(interaction, context.projectKey, this._storage)
2342
+ customerEmail: draft.customerEmail,
2343
+ lastMessageSequenceNumber: 0,
2344
+ orderNumber: draft.orderNumber,
2345
+ orderState: draft.orderState || "Open",
2346
+ origin: draft.origin || "Customer",
2347
+ paymentState: draft.paymentState,
2348
+ refusedGifts: [],
2349
+ shippingMode: "Single",
2350
+ shipping: [],
2351
+ store: resolveStoreReference(
2352
+ draft.store,
2353
+ context.projectKey,
2354
+ this._storage
2810
2355
  ),
2356
+ syncInfo: [],
2357
+ lineItems: ((_a = draft.lineItems) == null ? void 0 : _a.map(
2358
+ (item) => this.lineItemFromImportDraft.bind(this)(context, item)
2359
+ )) || [],
2360
+ customLineItems: ((_b = draft.customLineItems) == null ? void 0 : _b.map(
2361
+ (item) => this.customLineItemFromImportDraft.bind(this)(context, item)
2362
+ )) || [],
2363
+ totalPrice: {
2364
+ type: "centPrecision",
2365
+ ...draft.totalPrice,
2366
+ fractionDigits: 2
2367
+ }
2368
+ };
2369
+ this.saveNew(context, resource);
2370
+ return resource;
2371
+ }
2372
+ lineItemFromImportDraft(context, draft) {
2373
+ let product;
2374
+ let variant;
2375
+ if (draft.variant.sku) {
2376
+ variant = {
2377
+ id: 0,
2378
+ sku: draft.variant.sku
2379
+ };
2380
+ const items = this._storage.query(context.projectKey, "product", {
2381
+ where: [
2382
+ `masterData(current(masterVariant(sku="${draft.variant.sku}"))) or masterData(current(variants(sku="${draft.variant.sku}")))`
2383
+ ]
2384
+ });
2385
+ if (items.count !== 1) {
2386
+ throw new CommercetoolsError({
2387
+ code: "General",
2388
+ message: `A product containing a variant with SKU '${draft.variant.sku}' not found.`
2389
+ });
2390
+ }
2391
+ product = items.results[0];
2392
+ if (product.masterData.current.masterVariant.sku === draft.variant.sku) {
2393
+ variant = product.masterData.current.masterVariant;
2394
+ } else {
2395
+ variant = product.masterData.current.variants.find(
2396
+ (v) => v.sku === draft.variant.sku
2397
+ );
2398
+ }
2399
+ if (!variant) {
2400
+ throw new Error("Internal state error");
2401
+ }
2402
+ } else {
2403
+ throw new Error("No product found");
2404
+ }
2405
+ const lineItem = {
2406
+ ...getBaseResourceProperties(),
2811
2407
  custom: createCustomFields(
2812
2408
  draft.custom,
2813
2409
  context.projectKey,
2814
2410
  this._storage
2815
- )
2411
+ ),
2412
+ discountedPricePerQuantity: [],
2413
+ lineItemMode: "Standard",
2414
+ name: draft.name,
2415
+ price: createPrice(draft.price),
2416
+ priceMode: "Platform",
2417
+ productId: product.id,
2418
+ productType: product.productType,
2419
+ quantity: draft.quantity,
2420
+ state: draft.state || [],
2421
+ taxRate: draft.taxRate,
2422
+ taxedPricePortions: [],
2423
+ perMethodTaxRate: [],
2424
+ totalPrice: createTypedMoney(draft.price.value),
2425
+ variant: {
2426
+ id: variant.id,
2427
+ sku: variant.sku,
2428
+ price: createPrice(draft.price)
2429
+ }
2816
2430
  };
2817
- this.save(context, resource);
2818
- return resource;
2431
+ return lineItem;
2819
2432
  }
2820
- };
2821
-
2822
- // src/services/my-payment.ts
2823
- var MyPaymentService = class extends AbstractService {
2824
- constructor(parent, storage) {
2825
- super(parent);
2826
- this.repository = new PaymentRepository(storage);
2433
+ customLineItemFromImportDraft(context, draft) {
2434
+ const lineItem = {
2435
+ ...getBaseResourceProperties(),
2436
+ custom: createCustomFields(
2437
+ draft.custom,
2438
+ context.projectKey,
2439
+ this._storage
2440
+ ),
2441
+ discountedPricePerQuantity: [],
2442
+ money: createTypedMoney(draft.money),
2443
+ name: draft.name,
2444
+ quantity: draft.quantity,
2445
+ priceMode: draft.priceMode,
2446
+ slug: draft.slug,
2447
+ state: [],
2448
+ totalPrice: createTypedMoney(draft.money)
2449
+ };
2450
+ return lineItem;
2827
2451
  }
2828
- getBasePath() {
2829
- return "me/payments";
2452
+ getWithOrderNumber(context, orderNumber, params = {}) {
2453
+ const result = this._storage.query(context.projectKey, this.getTypeId(), {
2454
+ ...params,
2455
+ where: [`orderNumber="${orderNumber}"`]
2456
+ });
2457
+ if (result.count === 1) {
2458
+ return result.results[0];
2459
+ }
2460
+ if (result.count > 1) {
2461
+ throw new Error("Duplicate order numbers");
2462
+ }
2463
+ return;
2830
2464
  }
2831
2465
  };
2832
2466
 
2833
- // src/services/order.ts
2834
- var OrderService = class extends AbstractService {
2835
- constructor(parent, storage) {
2836
- super(parent);
2837
- this.repository = new OrderRepository(storage);
2838
- }
2839
- getBasePath() {
2840
- return "orders";
2841
- }
2842
- extraRoutes(router) {
2843
- router.post("/import", this.import.bind(this));
2844
- router.get("/order-number=:orderNumber", this.getWithOrderNumber.bind(this));
2845
- }
2846
- import(request, response) {
2847
- const importDraft = request.body;
2848
- const resource = this.repository.import(
2849
- getRepositoryContext(request),
2850
- importDraft
2851
- );
2852
- return response.status(200).send(resource);
2853
- }
2854
- getWithOrderNumber(request, response) {
2855
- const resource = this.repository.getWithOrderNumber(
2856
- getRepositoryContext(request),
2857
- request.params.orderNumber,
2858
- request.query
2859
- );
2860
- if (resource) {
2861
- return response.status(200).send(resource);
2862
- }
2863
- return response.status(404).send("Not found");
2467
+ // src/repositories/my-order.ts
2468
+ var MyOrderRepository = class extends OrderRepository {
2469
+ create(context, draft) {
2470
+ (0, import_assert3.default)(draft.id, "draft.id is missing");
2471
+ const cartIdentifier = {
2472
+ id: draft.id,
2473
+ typeId: "cart"
2474
+ };
2475
+ return this.createFromCart(context, cartIdentifier);
2864
2476
  }
2865
2477
  };
2866
2478
 
2867
- // src/services/payment.ts
2868
- var PaymentService = class extends AbstractService {
2869
- constructor(parent, storage) {
2870
- super(parent);
2871
- this.repository = new PaymentRepository(storage);
2479
+ // src/repositories/order-edit.ts
2480
+ var OrderEditRepository = class extends AbstractResourceRepository {
2481
+ constructor() {
2482
+ super(...arguments);
2483
+ this.actions = {};
2872
2484
  }
2873
- getBasePath() {
2874
- return "payments";
2485
+ getTypeId() {
2486
+ return "order-edit";
2487
+ }
2488
+ create(context, draft) {
2489
+ const resource = {
2490
+ ...getBaseResourceProperties(),
2491
+ stagedActions: draft.stagedActions ?? [],
2492
+ resource: draft.resource,
2493
+ result: {
2494
+ type: "NotProcessed"
2495
+ }
2496
+ };
2497
+ this.saveNew(context, resource);
2498
+ return resource;
2875
2499
  }
2876
2500
  };
2877
2501
 
2878
- // src/repositories/product-discount.ts
2879
- var ProductDiscountRepository = class extends AbstractResourceRepository {
2502
+ // src/repositories/payment.ts
2503
+ var import_uuid5 = require("uuid");
2504
+ var PaymentRepository = class extends AbstractResourceRepository {
2880
2505
  constructor() {
2881
2506
  super(...arguments);
2507
+ this.transactionFromTransactionDraft = (draft, context) => ({
2508
+ ...draft,
2509
+ id: (0, import_uuid5.v4)(),
2510
+ amount: createTypedMoney(draft.amount),
2511
+ custom: createCustomFields(draft.custom, context.projectKey, this._storage)
2512
+ });
2882
2513
  this.actions = {
2883
- setKey: (context, resource, { key }) => {
2884
- resource.key = key;
2514
+ setCustomField: (context, resource, { name, value }) => {
2515
+ if (!resource.custom) {
2516
+ throw new Error("Resource has no custom field");
2517
+ }
2518
+ resource.custom.fields[name] = value;
2885
2519
  },
2886
- setDescription: (context, resource, { description }) => {
2887
- if (description && Object.keys(description).length > 0) {
2888
- resource.description = description;
2520
+ setCustomType: (context, resource, { type, fields }) => {
2521
+ if (!type) {
2522
+ resource.custom = void 0;
2889
2523
  } else {
2890
- resource.description = void 0;
2524
+ const resolvedType = this._storage.getByResourceIdentifier(
2525
+ context.projectKey,
2526
+ type
2527
+ );
2528
+ if (!resolvedType) {
2529
+ throw new Error(`Type ${type} not found`);
2530
+ }
2531
+ resource.custom = {
2532
+ type: {
2533
+ typeId: "type",
2534
+ id: resolvedType.id
2535
+ },
2536
+ fields: fields || []
2537
+ };
2891
2538
  }
2892
2539
  },
2893
- changeName: (context, resource, { name }) => {
2894
- resource.name = name;
2895
- },
2896
- changeValue: (context, resource, { value }) => {
2897
- resource.value = this.transformValueDraft(value);
2898
- },
2899
- changePredicate: (context, resource, { predicate }) => {
2900
- resource.predicate = predicate;
2901
- },
2902
- changeSortOrder: (context, resource, { sortOrder }) => {
2903
- resource.sortOrder = sortOrder;
2904
- },
2905
- changeIsActive: (context, resource, { isActive }) => {
2906
- resource.isActive = isActive;
2907
- },
2908
- setValidFrom: (context, resource, { validFrom }) => {
2909
- resource.validFrom = validFrom;
2540
+ addTransaction: (context, resource, { transaction }) => {
2541
+ resource.transactions = [
2542
+ ...resource.transactions,
2543
+ this.transactionFromTransactionDraft(transaction, context)
2544
+ ];
2910
2545
  },
2911
- setValidUntil: (context, resource, { validUntil }) => {
2912
- resource.validUntil = validUntil;
2546
+ changeTransactionState: (_context, resource, { transactionId, state }) => {
2547
+ const index = resource.transactions.findIndex(
2548
+ (e) => e.id === transactionId
2549
+ );
2550
+ const updatedTransaction = {
2551
+ ...resource.transactions[index],
2552
+ state
2553
+ };
2554
+ resource.transactions[index] = updatedTransaction;
2913
2555
  },
2914
- setValidFromAndUntil: (context, resource, { validFrom, validUntil }) => {
2915
- resource.validFrom = validFrom;
2916
- resource.validUntil = validUntil;
2556
+ transitionState: (context, resource, { state }) => {
2557
+ const stateObj = this._storage.getByResourceIdentifier(
2558
+ context.projectKey,
2559
+ state
2560
+ );
2561
+ if (!stateObj) {
2562
+ throw new Error(`State ${state} not found`);
2563
+ }
2564
+ resource.paymentStatus.state = {
2565
+ typeId: "state",
2566
+ id: stateObj.id,
2567
+ obj: stateObj
2568
+ };
2917
2569
  }
2918
2570
  };
2919
2571
  }
2920
2572
  getTypeId() {
2921
- return "product-discount";
2573
+ return "payment";
2922
2574
  }
2923
2575
  create(context, draft) {
2924
2576
  const resource = {
2925
2577
  ...getBaseResourceProperties(),
2926
- key: draft.key,
2927
- name: draft.name,
2928
- description: draft.description,
2929
- value: this.transformValueDraft(draft.value),
2930
- predicate: draft.predicate,
2931
- sortOrder: draft.sortOrder,
2932
- isActive: draft.isActive || false,
2933
- validFrom: draft.validFrom,
2934
- validUntil: draft.validUntil,
2935
- references: []
2578
+ amountPlanned: createTypedMoney(draft.amountPlanned),
2579
+ paymentMethodInfo: draft.paymentMethodInfo,
2580
+ paymentStatus: draft.paymentStatus ? {
2581
+ ...draft.paymentStatus,
2582
+ state: draft.paymentStatus.state ? getReferenceFromResourceIdentifier(
2583
+ draft.paymentStatus.state,
2584
+ context.projectKey,
2585
+ this._storage
2586
+ ) : void 0
2587
+ } : {},
2588
+ transactions: (draft.transactions || []).map(
2589
+ (t) => this.transactionFromTransactionDraft(t, context)
2590
+ ),
2591
+ interfaceInteractions: (draft.interfaceInteractions || []).map(
2592
+ (interaction) => createCustomFields(interaction, context.projectKey, this._storage)
2593
+ ),
2594
+ custom: createCustomFields(
2595
+ draft.custom,
2596
+ context.projectKey,
2597
+ this._storage
2598
+ )
2936
2599
  };
2937
- this.save(context, resource);
2600
+ this.saveNew(context, resource);
2938
2601
  return resource;
2939
2602
  }
2940
- transformValueDraft(value) {
2941
- switch (value.type) {
2942
- case "absolute": {
2943
- return {
2944
- type: "absolute",
2945
- money: value.money.map(createTypedMoney)
2946
- };
2947
- }
2948
- case "external": {
2949
- return {
2950
- type: "external"
2951
- };
2952
- }
2953
- case "relative": {
2954
- return {
2955
- ...value
2956
- };
2957
- }
2958
- }
2959
- }
2960
- getWithKey(context, key) {
2961
- const result = this._storage.query(context.projectKey, this.getTypeId(), {
2962
- where: [`key="${key}"`]
2963
- });
2964
- if (result.count === 1) {
2965
- return result.results[0];
2966
- }
2967
- if (result.count > 1) {
2968
- throw new Error("Duplicate product discount key");
2969
- }
2970
- return;
2971
- }
2972
- };
2973
-
2974
- // src/services/product-discount.ts
2975
- var ProductDiscountService = class extends AbstractService {
2976
- constructor(parent, storage) {
2977
- super(parent);
2978
- this.repository = new ProductDiscountRepository(storage);
2979
- }
2980
- getBasePath() {
2981
- return "product-discounts";
2982
- }
2983
- extraRoutes(router) {
2984
- router.get("/key=:key", this.getWithKey.bind(this));
2985
- }
2986
- getWithKey(request, response) {
2987
- const resource = this.repository.getWithKey(
2988
- getRepositoryContext(request),
2989
- request.params.key
2990
- );
2991
- if (resource) {
2992
- return response.status(200).send(resource);
2993
- }
2994
- return response.status(404).send("Not found");
2995
- }
2996
2603
  };
2997
2604
 
2998
- // src/lib/projectionSearchFilter.ts
2605
+ // src/repositories/product.ts
2606
+ var import_uuid6 = require("uuid");
2607
+ var import_deep_equal2 = __toESM(require("deep-equal"));
2608
+ var ProductRepository = class extends AbstractResourceRepository {
2609
+ constructor() {
2610
+ super(...arguments);
2611
+ this.actions = {
2612
+ publish: (context, resource, { scope }) => {
2613
+ resource.masterData.current = resource.masterData.staged;
2614
+ resource.masterData.published = true;
2615
+ checkForStagedChanges(resource);
2616
+ },
2617
+ unpublish: (context, resource) => {
2618
+ resource.masterData.published = false;
2619
+ checkForStagedChanges(resource);
2620
+ },
2621
+ setAttribute: (context, resource, { variantId, sku, name, value, staged }) => {
2622
+ const setAttr = (data) => {
2623
+ const { variant, isMasterVariant, variantIndex } = getVariant(
2624
+ data,
2625
+ variantId,
2626
+ sku
2627
+ );
2628
+ if (!variant) {
2629
+ throw new Error(
2630
+ `Variant with id ${variantId} or sku ${sku} not found on product ${resource.id}`
2631
+ );
2632
+ }
2633
+ if (!variant.attributes) {
2634
+ variant.attributes = [];
2635
+ }
2636
+ const existingAttr = variant.attributes.find(
2637
+ (attr) => attr.name === name
2638
+ );
2639
+ if (existingAttr) {
2640
+ existingAttr.value = value;
2641
+ } else {
2642
+ variant.attributes.push({
2643
+ name,
2644
+ value
2645
+ });
2646
+ }
2647
+ if (isMasterVariant) {
2648
+ data.masterVariant = variant;
2649
+ } else {
2650
+ data.variants[variantIndex] = variant;
2651
+ }
2652
+ };
2653
+ const onlyStaged = staged !== void 0 ? staged : true;
2654
+ setAttr(resource.masterData.staged);
2655
+ if (!onlyStaged) {
2656
+ setAttr(resource.masterData.current);
2657
+ }
2658
+ checkForStagedChanges(resource);
2659
+ return resource;
2660
+ },
2661
+ setDescription: (context, resource, { description, staged }) => {
2662
+ const onlyStaged = staged !== void 0 ? staged : true;
2663
+ resource.masterData.staged.description = description;
2664
+ if (!onlyStaged) {
2665
+ resource.masterData.current.description = description;
2666
+ }
2667
+ checkForStagedChanges(resource);
2668
+ return resource;
2669
+ },
2670
+ setKey: (context, resource, { key }) => {
2671
+ resource.key = key;
2672
+ return resource;
2673
+ }
2674
+ };
2675
+ }
2676
+ getTypeId() {
2677
+ return "product";
2678
+ }
2679
+ create(context, draft) {
2680
+ var _a;
2681
+ if (!draft.masterVariant) {
2682
+ throw new Error("Missing master variant");
2683
+ }
2684
+ let productType = void 0;
2685
+ try {
2686
+ productType = getReferenceFromResourceIdentifier(
2687
+ draft.productType,
2688
+ context.projectKey,
2689
+ this._storage
2690
+ );
2691
+ } catch (err) {
2692
+ console.warn(
2693
+ `Error resolving product-type '${draft.productType.id}'. This will be throw an error in later releases.`
2694
+ );
2695
+ productType = {
2696
+ typeId: "product-type",
2697
+ id: draft.productType.id || ""
2698
+ };
2699
+ }
2700
+ const productData = {
2701
+ name: draft.name,
2702
+ slug: draft.slug,
2703
+ categories: [],
2704
+ masterVariant: variantFromDraft(1, draft.masterVariant),
2705
+ variants: ((_a = draft.variants) == null ? void 0 : _a.map(
2706
+ (variant, index) => variantFromDraft(index + 2, variant)
2707
+ )) ?? [],
2708
+ searchKeywords: draft.searchKeywords ?? {}
2709
+ };
2710
+ const resource = {
2711
+ ...getBaseResourceProperties(),
2712
+ key: draft.key,
2713
+ productType,
2714
+ masterData: {
2715
+ current: productData,
2716
+ staged: productData,
2717
+ hasStagedChanges: false,
2718
+ published: draft.publish ?? false
2719
+ }
2720
+ };
2721
+ this.saveNew(context, resource);
2722
+ return resource;
2723
+ }
2724
+ };
2725
+ var checkForStagedChanges = (product) => {
2726
+ if (!product.masterData.staged) {
2727
+ product.masterData.staged = product.masterData.current;
2728
+ }
2729
+ if ((0, import_deep_equal2.default)(product.masterData.current, product.masterData.staged)) {
2730
+ product.masterData.hasStagedChanges = false;
2731
+ } else {
2732
+ product.masterData.hasStagedChanges = true;
2733
+ }
2734
+ };
2735
+ var getVariant = (productData, variantId, sku) => {
2736
+ const variants = [productData.masterVariant, ...productData.variants];
2737
+ const foundVariant = variants.find((variant) => {
2738
+ if (variantId) {
2739
+ return variant.id === variantId;
2740
+ }
2741
+ if (sku) {
2742
+ return variant.sku === sku;
2743
+ }
2744
+ return false;
2745
+ });
2746
+ const isMasterVariant = foundVariant === productData.masterVariant;
2747
+ return {
2748
+ variant: foundVariant,
2749
+ isMasterVariant,
2750
+ variantIndex: !isMasterVariant && foundVariant ? productData.variants.indexOf(foundVariant) : -1
2751
+ };
2752
+ };
2753
+ var variantFromDraft = (variantId, variant) => {
2754
+ var _a;
2755
+ return {
2756
+ id: variantId,
2757
+ sku: variant == null ? void 0 : variant.sku,
2758
+ attributes: (variant == null ? void 0 : variant.attributes) ?? [],
2759
+ prices: (_a = variant == null ? void 0 : variant.prices) == null ? void 0 : _a.map(priceFromDraft),
2760
+ assets: [],
2761
+ images: []
2762
+ };
2763
+ };
2764
+ var priceFromDraft = (draft) => ({
2765
+ id: (0, import_uuid6.v4)(),
2766
+ value: {
2767
+ currencyCode: draft.value.currencyCode,
2768
+ centAmount: draft.value.centAmount,
2769
+ fractionDigits: 2,
2770
+ type: "centPrecision"
2771
+ }
2772
+ });
2773
+
2774
+ // src/repositories/product-discount.ts
2775
+ var ProductDiscountRepository = class extends AbstractResourceRepository {
2776
+ constructor() {
2777
+ super(...arguments);
2778
+ this.actions = {
2779
+ setKey: (context, resource, { key }) => {
2780
+ resource.key = key;
2781
+ },
2782
+ setDescription: (context, resource, { description }) => {
2783
+ if (description && Object.keys(description).length > 0) {
2784
+ resource.description = description;
2785
+ } else {
2786
+ resource.description = void 0;
2787
+ }
2788
+ },
2789
+ changeName: (context, resource, { name }) => {
2790
+ resource.name = name;
2791
+ },
2792
+ changeValue: (context, resource, { value }) => {
2793
+ resource.value = this.transformValueDraft(value);
2794
+ },
2795
+ changePredicate: (context, resource, { predicate }) => {
2796
+ resource.predicate = predicate;
2797
+ },
2798
+ changeSortOrder: (context, resource, { sortOrder }) => {
2799
+ resource.sortOrder = sortOrder;
2800
+ },
2801
+ changeIsActive: (context, resource, { isActive }) => {
2802
+ resource.isActive = isActive;
2803
+ },
2804
+ setValidFrom: (context, resource, { validFrom }) => {
2805
+ resource.validFrom = validFrom;
2806
+ },
2807
+ setValidUntil: (context, resource, { validUntil }) => {
2808
+ resource.validUntil = validUntil;
2809
+ },
2810
+ setValidFromAndUntil: (context, resource, { validFrom, validUntil }) => {
2811
+ resource.validFrom = validFrom;
2812
+ resource.validUntil = validUntil;
2813
+ }
2814
+ };
2815
+ }
2816
+ getTypeId() {
2817
+ return "product-discount";
2818
+ }
2819
+ create(context, draft) {
2820
+ const resource = {
2821
+ ...getBaseResourceProperties(),
2822
+ key: draft.key,
2823
+ name: draft.name,
2824
+ description: draft.description,
2825
+ value: this.transformValueDraft(draft.value),
2826
+ predicate: draft.predicate,
2827
+ sortOrder: draft.sortOrder,
2828
+ isActive: draft.isActive || false,
2829
+ validFrom: draft.validFrom,
2830
+ validUntil: draft.validUntil,
2831
+ references: []
2832
+ };
2833
+ this.saveNew(context, resource);
2834
+ return resource;
2835
+ }
2836
+ transformValueDraft(value) {
2837
+ switch (value.type) {
2838
+ case "absolute": {
2839
+ return {
2840
+ type: "absolute",
2841
+ money: value.money.map(createTypedMoney)
2842
+ };
2843
+ }
2844
+ case "external": {
2845
+ return {
2846
+ type: "external"
2847
+ };
2848
+ }
2849
+ case "relative": {
2850
+ return {
2851
+ ...value
2852
+ };
2853
+ }
2854
+ }
2855
+ }
2856
+ };
2857
+
2858
+ // src/lib/projectionSearchFilter.ts
2999
2859
  var import_perplex2 = __toESM(require("perplex"));
3000
2860
  var import_pratt2 = __toESM(require("pratt"));
3001
- var parseFilterExpression = (filter, staged) => {
2861
+ var parseFilterExpression = (filter) => {
3002
2862
  const exprFunc = generateMatchFunc2(filter);
3003
2863
  const [source] = filter.split(":", 1);
3004
2864
  if (source.startsWith("variants.")) {
3005
- return filterVariants(source, staged, exprFunc);
2865
+ return filterVariants(source, exprFunc);
3006
2866
  }
3007
2867
  return filterProduct(source, exprFunc);
3008
2868
  };
3009
- var getLexer2 = (value) => {
3010
- return new import_perplex2.default(value).token("MISSING", /missing(?![-_a-z0-9]+)/i).token("EXISTS", /exists(?![-_a-z0-9]+)/i).token("RANGE", /range(?![-_a-z0-9]+)/i).token("TO", /to(?![-_a-z0-9]+)/i).token("IDENTIFIER", /[-_\.a-z]+/i).token("FLOAT", /\d+\.\d+/).token("INT", /\d+/).token("STRING", /"((?:\\.|[^"\\])*)"/).token("STRING", /'((?:\\.|[^'\\])*)'/).token("COMMA", ",").token("STAR", "*").token("(", "(").token(":", ":").token(")", ")").token('"', '"').token("WS", /\s+/, true);
3011
- };
2869
+ var getLexer2 = (value) => new import_perplex2.default(value).token("MISSING", /missing(?![-_a-z0-9]+)/i).token("EXISTS", /exists(?![-_a-z0-9]+)/i).token("RANGE", /range(?![-_a-z0-9]+)/i).token("TO", /to(?![-_a-z0-9]+)/i).token("IDENTIFIER", /[-_.a-z]+/i).token("FLOAT", /\d+\.\d+/).token("INT", /\d+/).token("STRING", /"((?:\\.|[^"\\])*)"/).token("STRING", /'((?:\\.|[^'\\])*)'/).token("COMMA", ",").token("STAR", "*").token("(", "(").token(":", ":").token(")", ")").token('"', '"').token("WS", /\s+/, true);
3012
2870
  var parseFilter = (filter) => {
3013
2871
  const lexer = getLexer2(filter);
3014
- const parser = new import_pratt2.default(lexer).builder().nud("IDENTIFIER", 100, (t) => {
3015
- return t.token.match;
3016
- }).led(":", 100, ({ left, bp }) => {
3017
- let parsed = parser.parse({ terminals: [bp - 1] });
3018
- let expressions;
3019
- expressions = !Array.isArray(parsed) ? [parsed] : parsed;
2872
+ const parser = new import_pratt2.default(lexer).builder().nud("IDENTIFIER", 100, (t) => t.token.match).led(":", 100, ({ left, bp }) => {
2873
+ const parsed = parser.parse({ terminals: [bp - 1] });
2874
+ const expressions = !Array.isArray(parsed) ? [parsed] : parsed;
3020
2875
  const unique = new Set(expressions.map((expr) => expr.type));
3021
2876
  if (unique.size > 1) {
3022
2877
  throw new Error("Invalid expression");
@@ -3031,9 +2886,7 @@ var parseFilter = (filter) => {
3031
2886
  }
3032
2887
  return {
3033
2888
  type: "FilterExpression",
3034
- match: (obj) => {
3035
- return obj === e.value;
3036
- }
2889
+ match: (obj) => obj === e.value
3037
2890
  };
3038
2891
  })
3039
2892
  };
@@ -3043,39 +2896,41 @@ var parseFilter = (filter) => {
3043
2896
  type: expressions[0].type,
3044
2897
  children: expressions
3045
2898
  };
3046
- }).nud("STRING", 20, (t) => {
3047
- return {
2899
+ }).nud(
2900
+ "STRING",
2901
+ 20,
2902
+ (t) => ({
3048
2903
  type: "Symbol",
3049
2904
  kind: "string",
3050
2905
  value: t.token.groups[1]
3051
- };
3052
- }).nud("INT", 5, (t) => {
3053
- return {
2906
+ })
2907
+ ).nud(
2908
+ "INT",
2909
+ 5,
2910
+ (t) => ({
3054
2911
  type: "Symbol",
3055
2912
  kind: "int",
3056
2913
  value: parseInt(t.token.match, 10)
3057
- };
3058
- }).nud("STAR", 5, (t) => {
3059
- return {
3060
- type: "Symbol",
3061
- kind: "any",
3062
- value: null
3063
- };
3064
- }).nud("EXISTS", 10, ({ bp }) => {
3065
- return {
2914
+ })
2915
+ ).nud("STAR", 5, (_) => ({
2916
+ type: "Symbol",
2917
+ kind: "any",
2918
+ value: null
2919
+ })).nud(
2920
+ "EXISTS",
2921
+ 10,
2922
+ ({ bp }) => ({
3066
2923
  type: "FilterExpression",
3067
- match: (obj) => {
3068
- return obj !== void 0;
3069
- }
3070
- };
3071
- }).nud("MISSING", 10, ({ bp }) => {
3072
- return {
2924
+ match: (obj) => obj !== void 0
2925
+ })
2926
+ ).nud(
2927
+ "MISSING",
2928
+ 10,
2929
+ ({ bp }) => ({
3073
2930
  type: "FilterExpression",
3074
- match: (obj) => {
3075
- return obj === void 0;
3076
- }
3077
- };
3078
- }).led("COMMA", 200, ({ left, token, bp }) => {
2931
+ match: (obj) => obj === void 0
2932
+ })
2933
+ ).led("COMMA", 200, ({ left, token, bp }) => {
3079
2934
  const expr = parser.parse({ terminals: [bp - 1] });
3080
2935
  if (Array.isArray(expr)) {
3081
2936
  return [left, ...expr];
@@ -3100,21 +2955,13 @@ var parseFilter = (filter) => {
3100
2955
  return ranges.map((range) => {
3101
2956
  let func = void 0;
3102
2957
  if (range.start !== null && range.stop !== null) {
3103
- func = (obj) => {
3104
- return obj >= range.start && obj <= range.stop;
3105
- };
2958
+ func = (obj) => obj >= range.start && obj <= range.stop;
3106
2959
  } else if (range.start === null && range.stop !== null) {
3107
- func = (obj) => {
3108
- return obj <= range.stop;
3109
- };
2960
+ func = (obj) => obj <= range.stop;
3110
2961
  } else if (range.start !== null && range.stop === null) {
3111
- func = (obj) => {
3112
- return obj >= range.start;
3113
- };
2962
+ func = (obj) => obj >= range.start;
3114
2963
  } else {
3115
- func = (obj) => {
3116
- return true;
3117
- };
2964
+ func = (obj) => true;
3118
2965
  }
3119
2966
  return {
3120
2967
  type: "RangeExpression",
@@ -3129,8 +2976,6 @@ var parseFilter = (filter) => {
3129
2976
  var generateMatchFunc2 = (filter) => {
3130
2977
  const result = parseFilter(filter);
3131
2978
  if (!result) {
3132
- const lines = filter.split("\n");
3133
- const column = lines[lines.length - 1].length;
3134
2979
  throw new Error(`Syntax error while parsing '${filter}'.`);
3135
2980
  }
3136
2981
  if (result.type == "TermExpression") {
@@ -3151,29 +2996,25 @@ var generateFacetFunc = (filter) => {
3151
2996
  }
3152
2997
  return parseFilter(filter);
3153
2998
  };
3154
- var filterProduct = (source, exprFunc) => {
3155
- return (p, markMatchingVariants) => {
3156
- const value = nestedLookup(p, source);
3157
- return exprFunc(value);
3158
- };
2999
+ var filterProduct = (source, exprFunc) => (p, markMatchingVariants) => {
3000
+ const value = nestedLookup(p, source);
3001
+ return exprFunc(value);
3159
3002
  };
3160
- var filterVariants = (source, staged, exprFunc) => {
3161
- return (p, markMatchingVariants) => {
3162
- const [, ...paths] = source.split(".");
3163
- const path = paths.join(".");
3164
- const variants = getVariants(p, staged);
3165
- for (const variant of variants) {
3166
- const value = resolveVariantValue(variant, path);
3167
- if (exprFunc(value)) {
3168
- if (markMatchingVariants) {
3169
- variants.forEach((v) => v.isMatchingVariant = false);
3170
- variant.isMatchingVariant = true;
3171
- }
3172
- return true;
3003
+ var filterVariants = (source, exprFunc) => (p, markMatchingVariants) => {
3004
+ const [, ...paths] = source.split(".");
3005
+ const path = paths.join(".");
3006
+ const variants = getVariants(p);
3007
+ for (const variant of variants) {
3008
+ const value = resolveVariantValue(variant, path);
3009
+ if (exprFunc(value)) {
3010
+ if (markMatchingVariants) {
3011
+ variants.forEach((v) => v.isMatchingVariant = false);
3012
+ variant.isMatchingVariant = true;
3173
3013
  }
3014
+ return true;
3174
3015
  }
3175
- return false;
3176
- };
3016
+ }
3017
+ return false;
3177
3018
  };
3178
3019
  var resolveVariantValue = (obj, path) => {
3179
3020
  if (path === void 0) {
@@ -3198,27 +3039,22 @@ var resolveVariantValue = (obj, path) => {
3198
3039
  }
3199
3040
  return nestedLookup(obj, path);
3200
3041
  };
3201
- var getVariants = (p, staged) => {
3202
- var _a, _b, _c, _d;
3203
- return [
3204
- staged ? (_a = p.masterData.staged) == null ? void 0 : _a.masterVariant : (_b = p.masterData.current) == null ? void 0 : _b.masterVariant,
3205
- ...staged ? (_c = p.masterData.staged) == null ? void 0 : _c.variants : (_d = p.masterData.current) == null ? void 0 : _d.variants
3206
- ];
3207
- };
3042
+ var getVariants = (p) => [
3043
+ p.masterVariant,
3044
+ ...p.variants ?? []
3045
+ ];
3208
3046
 
3209
3047
  // src/priceSelector.ts
3210
3048
  var applyPriceSelector = (products, selector) => {
3211
- var _a, _b, _c, _d, _e;
3049
+ var _a;
3212
3050
  validatePriceSelector(selector);
3213
3051
  for (const product of products) {
3214
3052
  const variants = [
3215
- (_a = product.masterData.staged) == null ? void 0 : _a.masterVariant,
3216
- ...((_b = product.masterData.staged) == null ? void 0 : _b.variants) || [],
3217
- (_c = product.masterData.current) == null ? void 0 : _c.masterVariant,
3218
- ...((_d = product.masterData.current) == null ? void 0 : _d.variants) || []
3053
+ product.masterVariant,
3054
+ ...product.variants ?? []
3219
3055
  ].filter((x) => x != void 0);
3220
3056
  for (const variant of variants) {
3221
- const scopedPrices = ((_e = variant.prices) == null ? void 0 : _e.filter((p) => priceSelectorFilter(p, selector))) ?? [];
3057
+ const scopedPrices = ((_a = variant.prices) == null ? void 0 : _a.filter((p) => priceSelectorFilter(p, selector))) ?? [];
3222
3058
  if (scopedPrices.length > 0) {
3223
3059
  const price = scopedPrices[0];
3224
3060
  variant.scopedPriceDiscounted = false;
@@ -3264,8 +3100,13 @@ var ProductProjectionSearch = class {
3264
3100
  this._storage = storage;
3265
3101
  }
3266
3102
  search(projectKey, params) {
3267
- let resources = this._storage.all(projectKey, "product").map((r) => JSON.parse(JSON.stringify(r)));
3268
- let markMatchingVariant = params.markMatchingVariants ?? false;
3103
+ let resources = this._storage.all(projectKey, "product").map((r) => this.transform(r, params.staged ?? false)).filter((p) => {
3104
+ if (!params.staged) {
3105
+ return p.published;
3106
+ }
3107
+ return true;
3108
+ });
3109
+ const markMatchingVariant = params.markMatchingVariants ?? false;
3269
3110
  applyPriceSelector(resources, {
3270
3111
  country: params.priceCountry,
3271
3112
  channel: params.priceChannel,
@@ -3274,13 +3115,12 @@ var ProductProjectionSearch = class {
3274
3115
  });
3275
3116
  if (params.filter) {
3276
3117
  try {
3277
- const filters = params.filter.map(
3278
- (f) => parseFilterExpression(f, params.staged ?? false)
3279
- );
3118
+ const filters = params.filter.map(parseFilterExpression);
3280
3119
  resources = resources.filter(
3281
3120
  (resource) => filters.every((f) => f(resource, markMatchingVariant))
3282
3121
  );
3283
3122
  } catch (err) {
3123
+ console.error(err);
3284
3124
  throw new CommercetoolsError(
3285
3125
  {
3286
3126
  code: "InvalidInput",
@@ -3293,9 +3133,7 @@ var ProductProjectionSearch = class {
3293
3133
  const facets = this.getFacets(params, resources);
3294
3134
  if (params["filter.query"]) {
3295
3135
  try {
3296
- const filters = params["filter.query"].map(
3297
- (f) => parseFilterExpression(f, params.staged ?? false)
3298
- );
3136
+ const filters = params["filter.query"].map(parseFilterExpression);
3299
3137
  resources = resources.filter(
3300
3138
  (resource) => filters.every((f) => f(resource, markMatchingVariant))
3301
3139
  );
@@ -3309,26 +3147,26 @@ var ProductProjectionSearch = class {
3309
3147
  );
3310
3148
  }
3311
3149
  }
3312
- const totalResources = resources.length;
3313
- const offset = params.offset || 0;
3314
- const limit = params.limit || 20;
3315
- resources = resources.slice(offset, offset + limit);
3316
3150
  if (params.expand !== void 0) {
3317
- resources = resources.map((resource) => {
3318
- return this._storage.expand(projectKey, resource, params.expand);
3319
- });
3151
+ resources = resources.map(
3152
+ (resource) => this._storage.expand(projectKey, resource, params.expand)
3153
+ );
3320
3154
  }
3155
+ const totalResults = resources.length;
3156
+ const offset = params.offset || 0;
3157
+ const limit = params.limit || 20;
3158
+ const results = resources.slice(offset, offset + limit);
3321
3159
  return {
3322
- count: totalResources,
3323
- total: resources.length,
3160
+ count: totalResults,
3161
+ total: results.length,
3324
3162
  offset,
3325
3163
  limit,
3326
- results: resources.map(this.transform),
3164
+ results,
3327
3165
  facets
3328
3166
  };
3329
3167
  }
3330
- transform(product) {
3331
- const obj = product.masterData.current;
3168
+ transform(product, staged) {
3169
+ const obj = !staged ? product.masterData.current : product.masterData.staged;
3332
3170
  return {
3333
3171
  id: product.id,
3334
3172
  createdAt: product.createdAt,
@@ -3342,7 +3180,9 @@ var ProductProjectionSearch = class {
3342
3180
  categories: obj.categories,
3343
3181
  masterVariant: obj.masterVariant,
3344
3182
  variants: obj.variants,
3345
- productType: product.productType
3183
+ productType: product.productType,
3184
+ hasStagedChanges: product.masterData.hasStagedChanges,
3185
+ published: product.masterData.published
3346
3186
  };
3347
3187
  }
3348
3188
  getFacets(params, products) {
@@ -3353,28 +3193,26 @@ var ProductProjectionSearch = class {
3353
3193
  for (const facet of params.facet) {
3354
3194
  const expression = generateFacetFunc(facet);
3355
3195
  if (expression.type === "TermExpression") {
3356
- result[facet] = this.termFacet(expression.source, products, staged);
3196
+ result[facet] = this.termFacet(expression.source, products);
3357
3197
  }
3358
3198
  if (expression.type === "RangeExpression") {
3359
3199
  result[expression.source] = this.rangeFacet(
3360
3200
  expression.source,
3361
3201
  expression.children,
3362
- products,
3363
- staged
3202
+ products
3364
3203
  );
3365
3204
  }
3366
3205
  if (expression.type === "FilterExpression") {
3367
3206
  result[expression.source] = this.filterFacet(
3368
3207
  expression.source,
3369
3208
  expression.children,
3370
- products,
3371
- staged
3209
+ products
3372
3210
  );
3373
3211
  }
3374
3212
  }
3375
3213
  return result;
3376
3214
  }
3377
- termFacet(facet, products, staged) {
3215
+ termFacet(facet, products) {
3378
3216
  const result = {
3379
3217
  type: "terms",
3380
3218
  dataType: "text",
@@ -3386,7 +3224,7 @@ var ProductProjectionSearch = class {
3386
3224
  const terms = {};
3387
3225
  if (facet.startsWith("variants.")) {
3388
3226
  products.forEach((p) => {
3389
- const variants = getVariants(p, staged);
3227
+ const variants = getVariants(p);
3390
3228
  variants.forEach((v) => {
3391
3229
  result.total++;
3392
3230
  let value = resolveVariantValue(v, facet);
@@ -3419,11 +3257,11 @@ var ProductProjectionSearch = class {
3419
3257
  }
3420
3258
  return result;
3421
3259
  }
3422
- filterFacet(source, filters, products, staged) {
3260
+ filterFacet(source, filters, products) {
3423
3261
  let count = 0;
3424
3262
  if (source.startsWith("variants.")) {
3425
3263
  for (const p of products) {
3426
- for (const v of getVariants(p, staged)) {
3264
+ for (const v of getVariants(p)) {
3427
3265
  const val = resolveVariantValue(v, source);
3428
3266
  if (filters == null ? void 0 : filters.some((f) => f.match(val))) {
3429
3267
  count++;
@@ -3438,12 +3276,12 @@ var ProductProjectionSearch = class {
3438
3276
  count
3439
3277
  };
3440
3278
  }
3441
- rangeFacet(source, ranges, products, staged) {
3279
+ rangeFacet(source, ranges, products) {
3442
3280
  const counts = (ranges == null ? void 0 : ranges.map((range) => {
3443
3281
  if (source.startsWith("variants.")) {
3444
3282
  const values = [];
3445
3283
  for (const p of products) {
3446
- for (const v of getVariants(p, staged)) {
3284
+ for (const v of getVariants(p)) {
3447
3285
  const val = resolveVariantValue(v, source);
3448
3286
  if (val === void 0) {
3449
3287
  continue;
@@ -3500,12 +3338,18 @@ var ProductProjectionRepository = class extends AbstractResourceRepository {
3500
3338
  throw new Error("No valid action");
3501
3339
  }
3502
3340
  query(context, params = {}) {
3503
- return this._storage.query(context.projectKey, "product", {
3341
+ const response = this._storage.query(context.projectKey, "product", {
3504
3342
  expand: params.expand,
3505
3343
  where: params.where,
3506
3344
  offset: params.offset,
3507
3345
  limit: params.limit
3508
3346
  });
3347
+ return {
3348
+ ...response,
3349
+ results: response.results.map(
3350
+ (r) => this._searchService.transform(r, false)
3351
+ )
3352
+ };
3509
3353
  }
3510
3354
  search(context, query) {
3511
3355
  const results = this._searchService.search(context.projectKey, {
@@ -3514,210 +3358,45 @@ var ProductProjectionRepository = class extends AbstractResourceRepository {
3514
3358
  facet: QueryParamsAsArray(query.facet),
3515
3359
  offset: query.offset ? Number(query.offset) : void 0,
3516
3360
  limit: query.limit ? Number(query.limit) : void 0,
3517
- expand: QueryParamsAsArray(query.expand)
3361
+ expand: QueryParamsAsArray(query.expand),
3362
+ staged: query.staged === "true"
3518
3363
  });
3519
3364
  return results;
3520
3365
  }
3521
3366
  };
3522
3367
 
3523
- // src/services/product-projection.ts
3524
- var ProductProjectionService = class extends AbstractService {
3525
- constructor(parent, storage) {
3526
- super(parent);
3527
- this.repository = new ProductProjectionRepository(storage);
3528
- }
3529
- getBasePath() {
3530
- return "product-projections";
3531
- }
3532
- extraRoutes(router) {
3533
- router.get("/search", this.search.bind(this));
3534
- }
3535
- search(request, response) {
3536
- const resource = this.repository.search(
3537
- getRepositoryContext(request),
3538
- request.query
3539
- );
3540
- return response.status(200).send(resource);
3541
- }
3542
- };
3543
-
3544
- // src/repositories/product.ts
3545
- var import_uuid7 = require("uuid");
3546
- var ProductRepository = class extends AbstractResourceRepository {
3547
- constructor() {
3548
- super(...arguments);
3549
- this.actions = {
3550
- publish: (context, resource, { scope }) => {
3551
- if (resource.masterData.staged) {
3552
- resource.masterData.current = resource.masterData.staged;
3553
- resource.masterData.staged = void 0;
3554
- }
3555
- resource.masterData.hasStagedChanges = false;
3556
- resource.masterData.published = true;
3557
- },
3558
- setAttribute: (context, resource, { variantId, sku, name, value, staged }) => {
3559
- const isStaged = staged !== void 0 ? staged : false;
3560
- const productData = getProductData(resource, isStaged);
3561
- const { variant, isMasterVariant, variantIndex } = getVariant(
3562
- productData,
3563
- variantId,
3564
- sku
3565
- );
3566
- if (!variant) {
3567
- throw new Error(
3568
- `Variant with id ${variantId} or sku ${sku} not found on product ${resource.id}`
3569
- );
3570
- }
3571
- if (!variant.attributes) {
3572
- variant.attributes = [];
3573
- }
3574
- const existingAttr = variant.attributes.find((attr) => attr.name === name);
3575
- if (existingAttr) {
3576
- existingAttr.value = value;
3577
- } else {
3578
- variant.attributes.push({
3579
- name,
3580
- value
3581
- });
3582
- }
3583
- if (isStaged) {
3584
- resource.masterData.staged = productData;
3585
- if (isMasterVariant) {
3586
- resource.masterData.staged.masterVariant = variant;
3587
- } else {
3588
- resource.masterData.staged.variants[variantIndex] = variant;
3589
- }
3590
- resource.masterData.hasStagedChanges = true;
3591
- } else {
3592
- resource.masterData.current = productData;
3593
- if (isMasterVariant) {
3594
- resource.masterData.current.masterVariant = variant;
3595
- } else {
3596
- resource.masterData.current.variants[variantIndex] = variant;
3597
- }
3598
- }
3599
- }
3600
- };
3368
+ // src/repositories/product-selection.ts
3369
+ var ProductSelectionRepository = class extends AbstractResourceRepository {
3370
+ constructor() {
3371
+ super(...arguments);
3372
+ this.actions = {};
3601
3373
  }
3602
3374
  getTypeId() {
3603
- return "product";
3375
+ return "product-selection";
3604
3376
  }
3605
3377
  create(context, draft) {
3606
- var _a;
3607
- if (!draft.masterVariant) {
3608
- throw new Error("Missing master variant");
3609
- }
3610
- let productType = void 0;
3611
- try {
3612
- productType = getReferenceFromResourceIdentifier(
3613
- draft.productType,
3614
- context.projectKey,
3615
- this._storage
3616
- );
3617
- } catch (err) {
3618
- console.warn(
3619
- `Error resolving product-type '${draft.productType.id}'. This will be throw an error in later releases.`
3620
- );
3621
- productType = {
3622
- typeId: "product-type",
3623
- id: draft.productType.id || ""
3624
- };
3625
- }
3626
- const productData = {
3627
- name: draft.name,
3628
- slug: draft.slug,
3629
- categories: [],
3630
- masterVariant: variantFromDraft(1, draft.masterVariant),
3631
- variants: ((_a = draft.variants) == null ? void 0 : _a.map((variant, index) => {
3632
- return variantFromDraft(index + 2, variant);
3633
- })) ?? [],
3634
- searchKeywords: draft.searchKeywords
3635
- };
3636
3378
  const resource = {
3637
3379
  ...getBaseResourceProperties(),
3638
- productType,
3639
- masterData: {
3640
- current: draft.publish ? productData : void 0,
3641
- staged: draft.publish ? void 0 : productData,
3642
- hasStagedChanges: draft.publish ?? true,
3643
- published: draft.publish ?? false
3644
- }
3380
+ productCount: 0,
3381
+ name: draft.name,
3382
+ type: "individual"
3645
3383
  };
3646
- this.save(context, resource);
3384
+ this.saveNew(context, resource);
3647
3385
  return resource;
3648
3386
  }
3649
3387
  };
3650
- var getProductData = (product, staged) => {
3651
- if (!staged && product.masterData.current) {
3652
- return product.masterData.current;
3653
- }
3654
- return product.masterData.staged;
3655
- };
3656
- var getVariant = (productData, variantId, sku) => {
3657
- const variants = [productData.masterVariant, ...productData.variants];
3658
- const foundVariant = variants.find((variant) => {
3659
- if (variantId) {
3660
- return variant.id === variantId;
3661
- }
3662
- if (sku) {
3663
- return variant.sku === sku;
3664
- }
3665
- return false;
3666
- });
3667
- const isMasterVariant = foundVariant === productData.masterVariant;
3668
- return {
3669
- variant: foundVariant,
3670
- isMasterVariant,
3671
- variantIndex: !isMasterVariant && foundVariant ? productData.variants.indexOf(foundVariant) : -1
3672
- };
3673
- };
3674
- var variantFromDraft = (variantId, variant) => {
3675
- var _a;
3676
- return {
3677
- id: variantId,
3678
- sku: variant == null ? void 0 : variant.sku,
3679
- attributes: (variant == null ? void 0 : variant.attributes) ?? [],
3680
- prices: (_a = variant == null ? void 0 : variant.prices) == null ? void 0 : _a.map(priceFromDraft),
3681
- assets: [],
3682
- images: []
3683
- };
3684
- };
3685
- var priceFromDraft = (draft) => {
3686
- return {
3687
- id: (0, import_uuid7.v4)(),
3688
- value: {
3689
- currencyCode: draft.value.currencyCode,
3690
- centAmount: draft.value.centAmount,
3691
- fractionDigits: 2,
3692
- type: "centPrecision"
3693
- }
3694
- };
3695
- };
3696
-
3697
- // src/services/product.ts
3698
- var ProductService = class extends AbstractService {
3699
- constructor(parent, storage) {
3700
- super(parent);
3701
- this.repository = new ProductRepository(storage);
3702
- }
3703
- getBasePath() {
3704
- return "products";
3705
- }
3706
- };
3707
3388
 
3708
3389
  // src/repositories/product-type.ts
3709
3390
  var ProductTypeRepository = class extends AbstractResourceRepository {
3710
3391
  constructor() {
3711
3392
  super(...arguments);
3712
- this.attributeDefinitionFromAttributeDefinitionDraft = (_context, draft) => {
3713
- return {
3714
- ...draft,
3715
- attributeConstraint: draft.attributeConstraint ?? "None",
3716
- inputHint: draft.inputHint ?? "SingleLine",
3717
- inputTip: draft.inputTip && Object.keys(draft.inputTip).length > 0 ? draft.inputTip : void 0,
3718
- isSearchable: draft.isSearchable ?? true
3719
- };
3720
- };
3393
+ this.attributeDefinitionFromAttributeDefinitionDraft = (_context, draft) => ({
3394
+ ...draft,
3395
+ attributeConstraint: draft.attributeConstraint ?? "None",
3396
+ inputHint: draft.inputHint ?? "SingleLine",
3397
+ inputTip: draft.inputTip && Object.keys(draft.inputTip).length > 0 ? draft.inputTip : void 0,
3398
+ isSearchable: draft.isSearchable ?? true
3399
+ });
3721
3400
  this.actions = {
3722
3401
  changeLocalizedEnumValueLabel: (context, resource, {
3723
3402
  attributeName,
@@ -3758,20 +3437,20 @@ var ProductTypeRepository = class extends AbstractResourceRepository {
3758
3437
  this.attributeDefinitionFromAttributeDefinitionDraft(context, attribute)
3759
3438
  );
3760
3439
  },
3761
- changeAttributeOrder: (context, resource, { attributes }) => {
3440
+ changeAttributeOrderByName: (context, resource, { attributeNames }) => {
3762
3441
  var _a;
3763
- const attrs = new Map((_a = resource.attributes) == null ? void 0 : _a.map((item) => [item.name, item]));
3442
+ const attrs = new Map(
3443
+ (_a = resource.attributes) == null ? void 0 : _a.map((item) => [item.name, item])
3444
+ );
3764
3445
  const result = [];
3765
3446
  let current = resource.attributes;
3766
- attributes.forEach((iAttr) => {
3767
- const attr = attrs.get(iAttr.name);
3447
+ attributeNames.forEach((attrName) => {
3448
+ const attr = attrs.get(attrName);
3768
3449
  if (attr === void 0) {
3769
3450
  throw new Error("New attr");
3770
3451
  }
3771
3452
  result.push(attr);
3772
- current = current == null ? void 0 : current.filter((f) => {
3773
- return f.name !== iAttr.name;
3774
- });
3453
+ current = current == null ? void 0 : current.filter((f) => f.name !== attrName);
3775
3454
  });
3776
3455
  resource.attributes = result;
3777
3456
  if (current) {
@@ -3780,25 +3459,21 @@ var ProductTypeRepository = class extends AbstractResourceRepository {
3780
3459
  },
3781
3460
  removeAttributeDefinition: (context, resource, { name }) => {
3782
3461
  var _a;
3783
- resource.attributes = (_a = resource.attributes) == null ? void 0 : _a.filter((f) => {
3784
- return f.name !== name;
3785
- });
3462
+ resource.attributes = (_a = resource.attributes) == null ? void 0 : _a.filter((f) => f.name !== name);
3786
3463
  },
3787
3464
  removeEnumValues: (context, resource, { attributeName, keys }) => {
3788
3465
  var _a;
3789
3466
  (_a = resource.attributes) == null ? void 0 : _a.forEach((attr) => {
3790
3467
  if (attr.name == attributeName) {
3791
3468
  if (attr.type.name == "enum") {
3792
- attr.type.values = attr.type.values.filter((v) => {
3793
- return !keys.includes(v.key);
3794
- });
3469
+ attr.type.values = attr.type.values.filter(
3470
+ (v) => !keys.includes(v.key)
3471
+ );
3795
3472
  }
3796
3473
  if (attr.type.name == "set") {
3797
3474
  if (attr.type.elementType.name == "enum") {
3798
3475
  attr.type.elementType.values = attr.type.elementType.values.filter(
3799
- (v) => {
3800
- return !keys.includes(v.key);
3801
- }
3476
+ (v) => !keys.includes(v.key)
3802
3477
  );
3803
3478
  }
3804
3479
  }
@@ -3820,45 +3495,9 @@ var ProductTypeRepository = class extends AbstractResourceRepository {
3820
3495
  (a) => this.attributeDefinitionFromAttributeDefinitionDraft(context, a)
3821
3496
  )
3822
3497
  };
3823
- this.save(context, resource);
3498
+ this.saveNew(context, resource);
3824
3499
  return resource;
3825
3500
  }
3826
- getWithKey(context, key) {
3827
- const result = this._storage.query(context.projectKey, this.getTypeId(), {
3828
- where: [`key="${key}"`]
3829
- });
3830
- if (result.count === 1) {
3831
- return result.results[0];
3832
- }
3833
- if (result.count > 1) {
3834
- throw new Error("Duplicate product type key");
3835
- }
3836
- return;
3837
- }
3838
- };
3839
-
3840
- // src/services/product-type.ts
3841
- var ProductTypeService = class extends AbstractService {
3842
- constructor(parent, storage) {
3843
- super(parent);
3844
- this.repository = new ProductTypeRepository(storage);
3845
- }
3846
- getBasePath() {
3847
- return "product-types";
3848
- }
3849
- extraRoutes(router) {
3850
- router.get("/key=:key", this.getWithKey.bind(this));
3851
- }
3852
- getWithKey(request, response) {
3853
- const resource = this.repository.getWithKey(
3854
- getRepositoryContext(request),
3855
- request.params.key
3856
- );
3857
- if (resource) {
3858
- return response.status(200).send(resource);
3859
- }
3860
- return response.status(404).send("Not found");
3861
- }
3862
3501
  };
3863
3502
 
3864
3503
  // src/repositories/project.ts
@@ -3878,8 +3517,8 @@ var ProjectRepository = class extends AbstractRepository {
3878
3517
  changeLanguages: (context, resource, { languages }) => {
3879
3518
  resource.languages = languages;
3880
3519
  },
3881
- changeMessagesEnabled: (context, resource, { messagesEnabled }) => {
3882
- resource.messages.enabled = messagesEnabled;
3520
+ changeMessagesConfiguration: (context, resource, { messagesConfiguration }) => {
3521
+ resource.messages.enabled = messagesConfiguration.enabled;
3883
3522
  },
3884
3523
  changeProductSearchIndexingEnabled: (context, resource, { enabled }) => {
3885
3524
  var _a;
@@ -3922,64 +3561,68 @@ var ProjectRepository = class extends AbstractRepository {
3922
3561
  }
3923
3562
  postProcessResource(resource) {
3924
3563
  if (resource) {
3925
- return maskSecretValue(
3926
- resource,
3927
- "externalOAuth.authorizationHeader"
3928
- );
3564
+ return maskSecretValue(resource, "externalOAuth.authorizationHeader");
3929
3565
  }
3930
3566
  return resource;
3931
3567
  }
3932
- save(context, resource) {
3933
- const current = this.get(context);
3934
- if (current) {
3935
- checkConcurrentModification(current, resource.version);
3936
- } else {
3937
- if (resource.version !== 0) {
3938
- throw new CommercetoolsError(
3939
- {
3940
- code: "InvalidOperation",
3941
- message: "version on create must be 0"
3942
- },
3943
- 400
3944
- );
3945
- }
3946
- }
3947
- resource.version += 1;
3568
+ saveNew(context, resource) {
3569
+ resource.version = 1;
3570
+ this._storage.saveProject(resource);
3571
+ }
3572
+ saveUpdate(context, version, resource) {
3948
3573
  this._storage.saveProject(resource);
3949
3574
  }
3950
3575
  };
3951
3576
 
3952
- // src/services/project.ts
3953
- var ProjectService = class {
3954
- constructor(parent, storage) {
3955
- this.repository = new ProjectRepository(storage);
3956
- this.registerRoutes(parent);
3577
+ // src/repositories/quote.ts
3578
+ var QuoteRepository = class extends AbstractResourceRepository {
3579
+ constructor() {
3580
+ super(...arguments);
3581
+ this.actions = {};
3957
3582
  }
3958
- registerRoutes(parent) {
3959
- parent.get("", this.get.bind(this));
3960
- parent.post("", this.post.bind(this));
3583
+ getTypeId() {
3584
+ return "quote";
3961
3585
  }
3962
- get(request, response) {
3963
- const project = this.repository.get(getRepositoryContext(request));
3964
- return response.status(200).send(project);
3586
+ create(context, draft) {
3587
+ throw new Error("not implemented");
3965
3588
  }
3966
- post(request, response) {
3967
- const updateRequest = request.body;
3968
- const project = this.repository.get(getRepositoryContext(request));
3969
- if (!project) {
3970
- return response.status(404).send({});
3971
- }
3972
- this.repository.processUpdateActions(
3973
- getRepositoryContext(request),
3974
- project,
3975
- updateRequest.actions
3976
- );
3977
- return response.status(200).send({});
3589
+ };
3590
+
3591
+ // src/repositories/quote-request.ts
3592
+ var QuoteRequestRepository = class extends AbstractResourceRepository {
3593
+ constructor() {
3594
+ super(...arguments);
3595
+ this.actions = {};
3596
+ }
3597
+ getTypeId() {
3598
+ return "quote-request";
3599
+ }
3600
+ create(context, draft) {
3601
+ throw new Error("not implemented");
3602
+ }
3603
+ };
3604
+
3605
+ // src/repositories/review.ts
3606
+ var ReviewRepository = class extends AbstractResourceRepository {
3607
+ constructor() {
3608
+ super(...arguments);
3609
+ this.actions = {};
3610
+ }
3611
+ getTypeId() {
3612
+ return "review";
3613
+ }
3614
+ create(context, draft) {
3615
+ const resource = {
3616
+ ...getBaseResourceProperties(),
3617
+ includedInStatistics: false
3618
+ };
3619
+ this.saveNew(context, resource);
3620
+ return resource;
3978
3621
  }
3979
3622
  };
3980
3623
 
3981
3624
  // src/repositories/shipping-method.ts
3982
- var import_deep_equal2 = __toESM(require("deep-equal"));
3625
+ var import_deep_equal3 = __toESM(require("deep-equal"));
3983
3626
  var ShippingMethodRepository = class extends AbstractResourceRepository {
3984
3627
  constructor() {
3985
3628
  super(...arguments);
@@ -3995,13 +3638,11 @@ var ShippingMethodRepository = class extends AbstractResourceRepository {
3995
3638
  shippingRates: (_a = draft.shippingRates) == null ? void 0 : _a.map(this._transformShippingRate)
3996
3639
  };
3997
3640
  };
3998
- this._transformShippingRate = (rate) => {
3999
- return {
4000
- price: createTypedMoney(rate.price),
4001
- freeAbove: rate.freeAbove && createTypedMoney(rate.freeAbove),
4002
- tiers: rate.tiers || []
4003
- };
4004
- };
3641
+ this._transformShippingRate = (rate) => ({
3642
+ price: createTypedMoney(rate.price),
3643
+ freeAbove: rate.freeAbove && createTypedMoney(rate.freeAbove),
3644
+ tiers: rate.tiers || []
3645
+ });
4005
3646
  this.actions = {
4006
3647
  addShippingRate: (_context, resource, { shippingRate, zone }) => {
4007
3648
  const rate = this._transformShippingRate(shippingRate);
@@ -4023,9 +3664,9 @@ var ShippingMethodRepository = class extends AbstractResourceRepository {
4023
3664
  const rate = this._transformShippingRate(shippingRate);
4024
3665
  resource.zoneRates.forEach((zoneRate) => {
4025
3666
  if (zoneRate.zone.id === zone.id) {
4026
- zoneRate.shippingRates = zoneRate.shippingRates.filter((otherRate) => {
4027
- return !(0, import_deep_equal2.default)(rate, otherRate);
4028
- });
3667
+ zoneRate.shippingRates = zoneRate.shippingRates.filter(
3668
+ (otherRate) => !(0, import_deep_equal3.default)(rate, otherRate)
3669
+ );
4029
3670
  }
4030
3671
  });
4031
3672
  },
@@ -4044,9 +3685,9 @@ var ShippingMethodRepository = class extends AbstractResourceRepository {
4044
3685
  });
4045
3686
  },
4046
3687
  removeZone: (_context, resource, { zone }) => {
4047
- resource.zoneRates = resource.zoneRates.filter((zoneRate) => {
4048
- return zoneRate.zone.id !== zone.id;
4049
- });
3688
+ resource.zoneRates = resource.zoneRates.filter(
3689
+ (zoneRate) => zoneRate.zone.id !== zone.id
3690
+ );
4050
3691
  },
4051
3692
  setKey: (_context, resource, { key }) => {
4052
3693
  resource.key = key;
@@ -4111,26 +3752,11 @@ var ShippingMethodRepository = class extends AbstractResourceRepository {
4111
3752
  this._storage
4112
3753
  )
4113
3754
  };
4114
- this.save(context, resource);
3755
+ this.saveNew(context, resource);
4115
3756
  return resource;
4116
3757
  }
4117
3758
  };
4118
3759
 
4119
- // src/services/shipping-method.ts
4120
- var ShippingMethodService = class extends AbstractService {
4121
- constructor(parent, storage) {
4122
- super(parent);
4123
- this.repository = new ShippingMethodRepository(storage);
4124
- this.registerRoutes(parent);
4125
- }
4126
- getBasePath() {
4127
- return "shipping-methods";
4128
- }
4129
- extraRoutes(parent) {
4130
- parent.get("/matching-cart", this.get.bind(this));
4131
- }
4132
- };
4133
-
4134
3760
  // src/repositories/shopping-list.ts
4135
3761
  var ShoppingListRepository = class extends AbstractResourceRepository {
4136
3762
  getTypeId() {
@@ -4164,19 +3790,43 @@ var ShoppingListRepository = class extends AbstractResourceRepository {
4164
3790
  ) : void 0,
4165
3791
  store: ((_b = draft.store) == null ? void 0 : _b.key) ? { typeId: "store", key: draft.store.key } : void 0
4166
3792
  };
4167
- this.save(context, resource);
3793
+ this.saveNew(context, resource);
4168
3794
  return resource;
4169
3795
  }
4170
3796
  };
4171
3797
 
4172
- // src/services/shopping-list.ts
4173
- var ShoppingListService = class extends AbstractService {
4174
- constructor(parent, storage) {
4175
- super(parent);
4176
- this.repository = new ShoppingListRepository(storage);
3798
+ // src/repositories/staged-quote.ts
3799
+ var StagedQuoteRepository = class extends AbstractResourceRepository {
3800
+ constructor() {
3801
+ super(...arguments);
3802
+ this.actions = {};
4177
3803
  }
4178
- getBasePath() {
4179
- return "shopping-lists";
3804
+ getTypeId() {
3805
+ return "staged-quote";
3806
+ }
3807
+ create(context, draft) {
3808
+ throw new Error("not implemented");
3809
+ }
3810
+ };
3811
+
3812
+ // src/repositories/standalone-price.ts
3813
+ var StandAlonePriceRepository = class extends AbstractResourceRepository {
3814
+ constructor() {
3815
+ super(...arguments);
3816
+ this.actions = {};
3817
+ }
3818
+ getTypeId() {
3819
+ return "standalone-price";
3820
+ }
3821
+ create(context, draft) {
3822
+ const resource = {
3823
+ ...getBaseResourceProperties(),
3824
+ active: draft.active,
3825
+ sku: draft.sku,
3826
+ value: draft.value
3827
+ };
3828
+ this.saveNew(context, resource);
3829
+ return resource;
4180
3830
  }
4181
3831
  };
4182
3832
 
@@ -4198,12 +3848,12 @@ var StateRepository = class extends AbstractResourceRepository {
4198
3848
  resource.roles = roles;
4199
3849
  },
4200
3850
  setTransitions: (context, resource, { transitions }) => {
4201
- resource.transitions = transitions == null ? void 0 : transitions.map((resourceId) => {
4202
- return {
3851
+ resource.transitions = transitions == null ? void 0 : transitions.map(
3852
+ (resourceId) => ({
4203
3853
  id: resourceId.id || "",
4204
3854
  typeId: "state"
4205
- };
4206
- });
3855
+ })
3856
+ );
4207
3857
  }
4208
3858
  };
4209
3859
  }
@@ -4220,22 +3870,11 @@ var StateRepository = class extends AbstractResourceRepository {
4220
3870
  (t) => getReferenceFromResourceIdentifier(t, context.projectKey, this._storage)
4221
3871
  )
4222
3872
  };
4223
- this.save(context, resource);
3873
+ this.saveNew(context, resource);
4224
3874
  return resource;
4225
3875
  }
4226
3876
  };
4227
3877
 
4228
- // src/services/state.ts
4229
- var StateService = class extends AbstractService {
4230
- constructor(parent, storage) {
4231
- super(parent);
4232
- this.repository = new StateRepository(storage);
4233
- }
4234
- getBasePath() {
4235
- return "states";
4236
- }
4237
- };
4238
-
4239
3878
  // src/repositories/store.ts
4240
3879
  var StoreRepository = class extends AbstractResourceRepository {
4241
3880
  constructor() {
@@ -4297,7 +3936,7 @@ var StoreRepository = class extends AbstractResourceRepository {
4297
3936
  this._storage
4298
3937
  )
4299
3938
  };
4300
- this.save(context, resource);
3939
+ this.saveNew(context, resource);
4301
3940
  return resource;
4302
3941
  }
4303
3942
  transformChannels(context, channels) {
@@ -4311,42 +3950,6 @@ var StoreRepository = class extends AbstractResourceRepository {
4311
3950
  )
4312
3951
  );
4313
3952
  }
4314
- getWithKey(context, key) {
4315
- const result = this._storage.query(context.projectKey, this.getTypeId(), {
4316
- where: [`key="${key}"`]
4317
- });
4318
- if (result.count === 1) {
4319
- return result.results[0];
4320
- }
4321
- if (result.count > 1) {
4322
- throw new Error("Duplicate store key");
4323
- }
4324
- return;
4325
- }
4326
- };
4327
-
4328
- // src/services/store.ts
4329
- var StoreService = class extends AbstractService {
4330
- constructor(parent, storage) {
4331
- super(parent);
4332
- this.repository = new StoreRepository(storage);
4333
- }
4334
- getBasePath() {
4335
- return "stores";
4336
- }
4337
- extraRoutes(router) {
4338
- router.get("/key=:key", this.getWithKey.bind(this));
4339
- }
4340
- getWithKey(request, response) {
4341
- const resource = this.repository.getWithKey(
4342
- getRepositoryContext(request),
4343
- request.params.key
4344
- );
4345
- if (resource) {
4346
- return response.status(200).send(resource);
4347
- }
4348
- return response.status(404).send("Not found");
4349
- }
4350
3953
  };
4351
3954
 
4352
3955
  // src/repositories/subscription.ts
@@ -4380,30 +3983,19 @@ var SubscriptionRepository = class extends AbstractResourceRepository {
4380
3983
  messages: draft.messages || [],
4381
3984
  status: "Healthy"
4382
3985
  };
4383
- this.save(context, resource);
3986
+ this.saveNew(context, resource);
4384
3987
  return resource;
4385
3988
  }
4386
3989
  };
4387
3990
 
4388
- // src/services/subscription.ts
4389
- var SubscriptionService = class extends AbstractService {
4390
- constructor(parent, storage) {
4391
- super(parent);
4392
- this.repository = new SubscriptionRepository(storage);
4393
- }
4394
- getBasePath() {
4395
- return "subscriptions";
4396
- }
4397
- };
4398
-
4399
3991
  // src/repositories/tax-category.ts
4400
- var import_uuid8 = require("uuid");
3992
+ var import_uuid7 = require("uuid");
4401
3993
  var TaxCategoryRepository = class extends AbstractResourceRepository {
4402
3994
  constructor() {
4403
3995
  super(...arguments);
4404
3996
  this.taxRateFromTaxRateDraft = (draft) => ({
4405
3997
  ...draft,
4406
- id: (0, import_uuid8.v4)(),
3998
+ id: (0, import_uuid7.v4)(),
4407
3999
  amount: draft.amount || 0
4408
4000
  });
4409
4001
  this.actions = {
@@ -4417,9 +4009,9 @@ var TaxCategoryRepository = class extends AbstractResourceRepository {
4417
4009
  if (resource.rates === void 0) {
4418
4010
  resource.rates = [];
4419
4011
  }
4420
- resource.rates = resource.rates.filter((taxRate) => {
4421
- return taxRate.id !== taxRateId;
4422
- });
4012
+ resource.rates = resource.rates.filter(
4013
+ (taxRate) => taxRate.id !== taxRateId
4014
+ );
4423
4015
  },
4424
4016
  replaceTaxRate: (context, resource, { taxRateId, taxRate }) => {
4425
4017
  if (resource.rates === void 0) {
@@ -4454,45 +4046,9 @@ var TaxCategoryRepository = class extends AbstractResourceRepository {
4454
4046
  ...draft,
4455
4047
  rates: ((_a = draft.rates) == null ? void 0 : _a.map(this.taxRateFromTaxRateDraft)) || []
4456
4048
  };
4457
- this.save(context, resource);
4049
+ this.saveNew(context, resource);
4458
4050
  return resource;
4459
4051
  }
4460
- getWithKey(context, key) {
4461
- const result = this._storage.query(context.projectKey, this.getTypeId(), {
4462
- where: [`key="${key}"`]
4463
- });
4464
- if (result.count === 1) {
4465
- return result.results[0];
4466
- }
4467
- if (result.count > 1) {
4468
- throw new Error("Duplicate tax category key");
4469
- }
4470
- return;
4471
- }
4472
- };
4473
-
4474
- // src/services/tax-category.ts
4475
- var TaxCategoryService = class extends AbstractService {
4476
- constructor(parent, storage) {
4477
- super(parent);
4478
- this.repository = new TaxCategoryRepository(storage);
4479
- }
4480
- getBasePath() {
4481
- return "tax-categories";
4482
- }
4483
- extraRoutes(router) {
4484
- router.get("/key=:key", this.getWithKey.bind(this));
4485
- }
4486
- getWithKey(request, response) {
4487
- const resource = this.repository.getWithKey(
4488
- getRepositoryContext(request),
4489
- request.params.key
4490
- );
4491
- if (resource) {
4492
- return response.status(200).send(resource);
4493
- }
4494
- return response.status(404).send("Not found");
4495
- }
4496
4052
  };
4497
4053
 
4498
4054
  // src/repositories/type.ts
@@ -4505,9 +4061,9 @@ var TypeRepository = class extends AbstractResourceRepository {
4505
4061
  resource.fieldDefinitions.push(fieldDefinition);
4506
4062
  },
4507
4063
  removeFieldDefinition: (context, resource, { fieldName }) => {
4508
- resource.fieldDefinitions = resource.fieldDefinitions.filter((f) => {
4509
- return f.name !== fieldName;
4510
- });
4064
+ resource.fieldDefinitions = resource.fieldDefinitions.filter(
4065
+ (f) => f.name !== fieldName
4066
+ );
4511
4067
  },
4512
4068
  setDescription: (context, resource, { description }) => {
4513
4069
  resource.description = description;
@@ -4527,9 +4083,7 @@ var TypeRepository = class extends AbstractResourceRepository {
4527
4083
  throw new Error("New field");
4528
4084
  }
4529
4085
  result.push(field);
4530
- current = current.filter((f) => {
4531
- return f.name !== fieldName;
4532
- });
4086
+ current = current.filter((f) => f.name !== fieldName);
4533
4087
  });
4534
4088
  if ((0, import_lodash.isEqual)(
4535
4089
  fieldNames,
@@ -4595,22 +4149,11 @@ var TypeRepository = class extends AbstractResourceRepository {
4595
4149
  fieldDefinitions: draft.fieldDefinitions || [],
4596
4150
  description: draft.description
4597
4151
  };
4598
- this.save(context, resource);
4152
+ this.saveNew(context, resource);
4599
4153
  return resource;
4600
4154
  }
4601
4155
  };
4602
4156
 
4603
- // src/services/type.ts
4604
- var TypeService = class extends AbstractService {
4605
- constructor(parent, storage) {
4606
- super(parent);
4607
- this.repository = new TypeRepository(storage);
4608
- }
4609
- getBasePath() {
4610
- return "types";
4611
- }
4612
- };
4613
-
4614
4157
  // src/repositories/zone.ts
4615
4158
  var ZoneRepository = class extends AbstractResourceRepository {
4616
4159
  constructor() {
@@ -4620,9 +4163,9 @@ var ZoneRepository = class extends AbstractResourceRepository {
4620
4163
  resource.locations.push(location);
4621
4164
  },
4622
4165
  removeLocation: (context, resource, { location }) => {
4623
- resource.locations = resource.locations.filter((loc) => {
4624
- return !(loc.country === location.country && loc.state === location.state);
4625
- });
4166
+ resource.locations = resource.locations.filter(
4167
+ (loc) => !(loc.country === location.country && loc.state === location.state)
4168
+ );
4626
4169
  },
4627
4170
  changeName: (context, resource, { name }) => {
4628
4171
  resource.name = name;
@@ -4635,39 +4178,438 @@ var ZoneRepository = class extends AbstractResourceRepository {
4635
4178
  }
4636
4179
  };
4637
4180
  }
4638
- getTypeId() {
4639
- return "zone";
4181
+ getTypeId() {
4182
+ return "zone";
4183
+ }
4184
+ create(context, draft) {
4185
+ const resource = {
4186
+ ...getBaseResourceProperties(),
4187
+ key: draft.key,
4188
+ locations: draft.locations || [],
4189
+ name: draft.name,
4190
+ description: draft.description
4191
+ };
4192
+ this.saveNew(context, resource);
4193
+ return resource;
4194
+ }
4195
+ };
4196
+
4197
+ // src/repositories/index.ts
4198
+ var createRepositories = (storage) => ({
4199
+ category: new CategoryRepository(storage),
4200
+ cart: new CartRepository(storage),
4201
+ "cart-discount": new CartDiscountRepository(storage),
4202
+ customer: new CustomerRepository(storage),
4203
+ channel: new ChannelRepository(storage),
4204
+ "customer-group": new CustomerGroupRepository(storage),
4205
+ "discount-code": new DiscountCodeRepository(storage),
4206
+ extension: new ExtensionRepository(storage),
4207
+ "inventory-entry": new InventoryEntryRepository(storage),
4208
+ "key-value-document": new CustomObjectRepository(storage),
4209
+ order: new OrderRepository(storage),
4210
+ "order-edit": new OrderEditRepository(storage),
4211
+ payment: new PaymentRepository(storage),
4212
+ "my-cart": new CartRepository(storage),
4213
+ "my-order": new MyOrderRepository(storage),
4214
+ "my-customer": new CustomerRepository(storage),
4215
+ "my-payment": new PaymentRepository(storage),
4216
+ product: new ProductRepository(storage),
4217
+ "product-type": new ProductTypeRepository(storage),
4218
+ "product-discount": new ProductDiscountRepository(storage),
4219
+ "product-projection": new ProductProjectionRepository(storage),
4220
+ "product-selection": new ProductSelectionRepository(storage),
4221
+ project: new ProjectRepository(storage),
4222
+ review: new ReviewRepository(storage),
4223
+ quote: new QuoteRepository(storage),
4224
+ "quote-request": new QuoteRequestRepository(storage),
4225
+ "shipping-method": new ShippingMethodRepository(storage),
4226
+ "shopping-list": new ShoppingListRepository(storage),
4227
+ "staged-quote": new StagedQuoteRepository(storage),
4228
+ "standalone-price": new StandAlonePriceRepository(storage),
4229
+ state: new StateRepository(storage),
4230
+ store: new StoreRepository(storage),
4231
+ subscription: new SubscriptionRepository(storage),
4232
+ "tax-category": new TaxCategoryRepository(storage),
4233
+ type: new TypeRepository(storage),
4234
+ zone: new ZoneRepository(storage)
4235
+ });
4236
+
4237
+ // src/services/abstract.ts
4238
+ var import_express2 = require("express");
4239
+ var AbstractService = class {
4240
+ constructor(parent) {
4241
+ this.createStatusCode = 201;
4242
+ this.registerRoutes(parent);
4243
+ }
4244
+ extraRoutes(router) {
4245
+ }
4246
+ registerRoutes(parent) {
4247
+ const basePath = this.getBasePath();
4248
+ const router = (0, import_express2.Router)({ mergeParams: true });
4249
+ this.extraRoutes(router);
4250
+ router.get("/", this.get.bind(this));
4251
+ router.get("/key=:key", this.getWithKey.bind(this));
4252
+ router.get("/:id", this.getWithId.bind(this));
4253
+ router.delete("/key=:key", this.deleteWithKey.bind(this));
4254
+ router.delete("/:id", this.deleteWithId.bind(this));
4255
+ router.post("/", this.post.bind(this));
4256
+ router.post("/key=:key", this.postWithKey.bind(this));
4257
+ router.post("/:id", this.postWithId.bind(this));
4258
+ parent.use(`/${basePath}`, router);
4259
+ }
4260
+ get(request, response) {
4261
+ const limit = this._parseParam(request.query.limit);
4262
+ const offset = this._parseParam(request.query.offset);
4263
+ const result = this.repository.query(getRepositoryContext(request), {
4264
+ expand: this._parseParam(request.query.expand),
4265
+ where: this._parseParam(request.query.where),
4266
+ limit: limit !== void 0 ? Number(limit) : void 0,
4267
+ offset: offset !== void 0 ? Number(offset) : void 0
4268
+ });
4269
+ return response.status(200).send(result);
4270
+ }
4271
+ getWithId(request, response) {
4272
+ const result = this._expandWithId(request, request.params["id"]);
4273
+ if (!result) {
4274
+ return response.status(404).send();
4275
+ }
4276
+ return response.status(200).send(result);
4277
+ }
4278
+ getWithKey(request, response) {
4279
+ const result = this.repository.getByKey(
4280
+ getRepositoryContext(request),
4281
+ request.params["key"],
4282
+ { expand: this._parseParam(request.query.expand) }
4283
+ );
4284
+ if (!result)
4285
+ return response.status(404).send();
4286
+ return response.status(200).send(result);
4287
+ }
4288
+ deleteWithId(request, response) {
4289
+ const result = this.repository.delete(
4290
+ getRepositoryContext(request),
4291
+ request.params["id"],
4292
+ {
4293
+ expand: this._parseParam(request.query.expand)
4294
+ }
4295
+ );
4296
+ if (!result) {
4297
+ return response.status(404).send("Not found");
4298
+ }
4299
+ return response.status(200).send(result);
4300
+ }
4301
+ deleteWithKey(request, response) {
4302
+ const resource = this.repository.getByKey(
4303
+ getRepositoryContext(request),
4304
+ request.params["key"]
4305
+ );
4306
+ if (!resource) {
4307
+ return response.status(404).send("Not found");
4308
+ }
4309
+ const result = this.repository.delete(
4310
+ getRepositoryContext(request),
4311
+ resource.id,
4312
+ {
4313
+ expand: this._parseParam(request.query.expand)
4314
+ }
4315
+ );
4316
+ if (!result) {
4317
+ return response.status(404).send("Not found");
4318
+ }
4319
+ return response.status(200).send(result);
4320
+ }
4321
+ post(request, response) {
4322
+ const draft = request.body;
4323
+ const resource = this.repository.create(
4324
+ getRepositoryContext(request),
4325
+ draft
4326
+ );
4327
+ const result = this._expandWithId(request, resource.id);
4328
+ return response.status(this.createStatusCode).send(result);
4329
+ }
4330
+ postWithId(request, response) {
4331
+ const updateRequest = request.body;
4332
+ const resource = this.repository.get(
4333
+ getRepositoryContext(request),
4334
+ request.params["id"]
4335
+ );
4336
+ if (!resource) {
4337
+ return response.status(404).send("Not found");
4338
+ }
4339
+ const updatedResource = this.repository.processUpdateActions(
4340
+ getRepositoryContext(request),
4341
+ resource,
4342
+ updateRequest.version,
4343
+ updateRequest.actions
4344
+ );
4345
+ const result = this._expandWithId(request, updatedResource.id);
4346
+ return response.status(200).send(result);
4347
+ }
4348
+ postWithKey(request, response) {
4349
+ const updateRequest = request.body;
4350
+ const resource = this.repository.getByKey(
4351
+ getRepositoryContext(request),
4352
+ request.params["key"]
4353
+ );
4354
+ if (!resource) {
4355
+ return response.status(404).send("Not found");
4356
+ }
4357
+ const updatedResource = this.repository.processUpdateActions(
4358
+ getRepositoryContext(request),
4359
+ resource,
4360
+ updateRequest.version,
4361
+ updateRequest.actions
4362
+ );
4363
+ const result = this._expandWithId(request, updatedResource.id);
4364
+ return response.status(200).send(result);
4365
+ }
4366
+ _expandWithId(request, resourceId) {
4367
+ const result = this.repository.get(
4368
+ getRepositoryContext(request),
4369
+ resourceId,
4370
+ {
4371
+ expand: this._parseParam(request.query.expand)
4372
+ }
4373
+ );
4374
+ return result;
4375
+ }
4376
+ _parseParam(value) {
4377
+ if (Array.isArray(value)) {
4378
+ return value;
4379
+ } else if (value !== void 0) {
4380
+ return [`${value}`];
4381
+ }
4382
+ return void 0;
4383
+ }
4384
+ };
4385
+
4386
+ // src/services/cart.ts
4387
+ var CartService = class extends AbstractService {
4388
+ constructor(parent, cartRepository, orderRepository) {
4389
+ super(parent);
4390
+ this.repository = cartRepository;
4391
+ this.orderRepository = orderRepository;
4392
+ }
4393
+ getBasePath() {
4394
+ return "carts";
4395
+ }
4396
+ extraRoutes(parent) {
4397
+ parent.post("/replicate", this.replicate.bind(this));
4398
+ }
4399
+ replicate(request, response) {
4400
+ const context = getRepositoryContext(request);
4401
+ const cartOrOrder = request.body.reference.typeId === "order" ? this.orderRepository.get(context, request.body.reference.id) : this.repository.get(context, request.body.reference.id);
4402
+ if (!cartOrOrder) {
4403
+ return response.status(400).send();
4404
+ }
4405
+ const cartDraft = {
4406
+ ...cartOrOrder,
4407
+ currency: cartOrOrder.totalPrice.currencyCode,
4408
+ discountCodes: [],
4409
+ shipping: [],
4410
+ lineItems: cartOrOrder.lineItems.map((lineItem) => ({
4411
+ ...lineItem,
4412
+ variantId: lineItem.variant.id,
4413
+ sku: lineItem.variant.sku
4414
+ }))
4415
+ };
4416
+ const newCart = this.repository.create(context, cartDraft);
4417
+ return response.status(200).send(newCart);
4418
+ }
4419
+ };
4420
+
4421
+ // src/services/cart-discount.ts
4422
+ var CartDiscountService = class extends AbstractService {
4423
+ constructor(parent, repository) {
4424
+ super(parent);
4425
+ this.repository = repository;
4426
+ }
4427
+ getBasePath() {
4428
+ return "cart-discounts";
4429
+ }
4430
+ };
4431
+
4432
+ // src/services/category.ts
4433
+ var CategoryServices = class extends AbstractService {
4434
+ constructor(parent, repository) {
4435
+ super(parent);
4436
+ this.repository = repository;
4437
+ }
4438
+ getBasePath() {
4439
+ return "categories";
4440
+ }
4441
+ };
4442
+
4443
+ // src/services/channel.ts
4444
+ var ChannelService = class extends AbstractService {
4445
+ constructor(parent, repository) {
4446
+ super(parent);
4447
+ this.repository = repository;
4448
+ }
4449
+ getBasePath() {
4450
+ return "channels";
4451
+ }
4452
+ };
4453
+
4454
+ // src/services/custom-object.ts
4455
+ var CustomObjectService = class extends AbstractService {
4456
+ constructor(parent, repository) {
4457
+ super(parent);
4458
+ this.repository = repository;
4459
+ }
4460
+ getBasePath() {
4461
+ return "custom-objects";
4462
+ }
4463
+ extraRoutes(router) {
4464
+ router.get("/:container/:key", this.getWithContainerAndKey.bind(this));
4465
+ router.post("/:container/:key", this.createWithContainerAndKey.bind(this));
4466
+ router.delete("/:container/:key", this.deleteWithContainerAndKey.bind(this));
4467
+ }
4468
+ getWithContainerAndKey(request, response) {
4469
+ const result = this.repository.getWithContainerAndKey(
4470
+ getRepositoryContext(request),
4471
+ request.params.container,
4472
+ request.params.key
4473
+ );
4474
+ if (!result) {
4475
+ return response.status(404).send("Not Found");
4476
+ }
4477
+ return response.status(200).send(result);
4478
+ }
4479
+ createWithContainerAndKey(request, response) {
4480
+ const draft = {
4481
+ ...request.body,
4482
+ key: request.params.key,
4483
+ container: request.params.container
4484
+ };
4485
+ const result = this.repository.create(getRepositoryContext(request), draft);
4486
+ return response.status(200).send(result);
4487
+ }
4488
+ deleteWithContainerAndKey(request, response) {
4489
+ const current = this.repository.getWithContainerAndKey(
4490
+ getRepositoryContext(request),
4491
+ request.params.container,
4492
+ request.params.key
4493
+ );
4494
+ if (!current) {
4495
+ return response.status(404).send("Not Found");
4496
+ }
4497
+ const result = this.repository.delete(
4498
+ getRepositoryContext(request),
4499
+ current.id
4500
+ );
4501
+ return response.status(200).send(result);
4502
+ }
4503
+ };
4504
+
4505
+ // src/services/customer.ts
4506
+ var import_uuid8 = require("uuid");
4507
+ var CustomerService = class extends AbstractService {
4508
+ constructor(parent, repository) {
4509
+ super(parent);
4510
+ this.repository = repository;
4511
+ }
4512
+ getBasePath() {
4513
+ return "customers";
4514
+ }
4515
+ extraRoutes(parent) {
4516
+ parent.post("/password-token", (request, response) => {
4517
+ const customer = this.repository.query(getRepositoryContext(request), {
4518
+ where: [`email="${request.body.email}"`]
4519
+ });
4520
+ const ttlMinutes = request.params.ttlMinutes ? +request.params.ttlMinutes : 34560;
4521
+ const { version, ...rest } = getBaseResourceProperties();
4522
+ return response.status(200).send({
4523
+ ...rest,
4524
+ customerId: customer.results[0].id,
4525
+ expiresAt: new Date(Date.now() + ttlMinutes * 60).toISOString(),
4526
+ value: (0, import_uuid8.v4)()
4527
+ });
4528
+ });
4529
+ }
4530
+ };
4531
+
4532
+ // src/services/customer-group.ts
4533
+ var CustomerGroupService = class extends AbstractService {
4534
+ constructor(parent, repository) {
4535
+ super(parent);
4536
+ this.repository = repository;
4537
+ }
4538
+ getBasePath() {
4539
+ return "customer-groups";
4540
+ }
4541
+ };
4542
+
4543
+ // src/services/discount-code.ts
4544
+ var DiscountCodeService = class extends AbstractService {
4545
+ constructor(parent, repository) {
4546
+ super(parent);
4547
+ this.repository = repository;
4548
+ }
4549
+ getBasePath() {
4550
+ return "discount-codes";
4551
+ }
4552
+ };
4553
+
4554
+ // src/services/extension.ts
4555
+ var ExtensionServices = class extends AbstractService {
4556
+ constructor(parent, repository) {
4557
+ super(parent);
4558
+ this.repository = repository;
4640
4559
  }
4641
- create(context, draft) {
4642
- const resource = {
4643
- ...getBaseResourceProperties(),
4644
- key: draft.key,
4645
- locations: draft.locations || [],
4646
- name: draft.name,
4647
- description: draft.description
4648
- };
4649
- this.save(context, resource);
4650
- return resource;
4560
+ getBasePath() {
4561
+ return "extensions";
4651
4562
  }
4652
4563
  };
4653
4564
 
4654
- // src/services/zone.ts
4655
- var ZoneService = class extends AbstractService {
4656
- constructor(parent, storage) {
4565
+ // src/services/inventory-entry.ts
4566
+ var InventoryEntryService = class extends AbstractService {
4567
+ constructor(parent, repository) {
4657
4568
  super(parent);
4658
- this.repository = new ZoneRepository(storage);
4569
+ this.repository = repository;
4659
4570
  }
4660
4571
  getBasePath() {
4661
- return "zones";
4572
+ return "inventory";
4573
+ }
4574
+ };
4575
+
4576
+ // src/services/my-cart.ts
4577
+ var import_express3 = require("express");
4578
+ var MyCartService = class extends AbstractService {
4579
+ constructor(parent, repository) {
4580
+ super(parent);
4581
+ this.repository = repository;
4582
+ }
4583
+ getBasePath() {
4584
+ return "me";
4585
+ }
4586
+ registerRoutes(parent) {
4587
+ const basePath = this.getBasePath();
4588
+ const router = (0, import_express3.Router)({ mergeParams: true });
4589
+ this.extraRoutes(router);
4590
+ router.get("/active-cart", this.activeCart.bind(this));
4591
+ router.get("/carts/", this.get.bind(this));
4592
+ router.get("/carts/:id", this.getWithId.bind(this));
4593
+ router.delete("/carts/:id", this.deleteWithId.bind(this));
4594
+ router.post("/carts/", this.post.bind(this));
4595
+ router.post("/carts/:id", this.postWithId.bind(this));
4596
+ parent.use(`/${basePath}`, router);
4597
+ }
4598
+ activeCart(request, response) {
4599
+ const resource = this.repository.getActiveCart(request.params.projectKey);
4600
+ if (!resource) {
4601
+ return response.status(404).send("Not found");
4602
+ }
4603
+ return response.status(200).send(resource);
4662
4604
  }
4663
4605
  };
4664
4606
 
4665
4607
  // src/services/my-customer.ts
4666
4608
  var import_express4 = require("express");
4667
4609
  var MyCustomerService = class extends AbstractService {
4668
- constructor(parent, storage) {
4610
+ constructor(parent, repository) {
4669
4611
  super(parent);
4670
- this.repository = new CustomerRepository(storage);
4612
+ this.repository = repository;
4671
4613
  }
4672
4614
  getBasePath() {
4673
4615
  return "me";
@@ -4720,25 +4662,10 @@ var MyCustomerService = class extends AbstractService {
4720
4662
 
4721
4663
  // src/services/my-order.ts
4722
4664
  var import_express5 = require("express");
4723
-
4724
- // src/repositories/my-order.ts
4725
- var import_assert3 = __toESM(require("assert"));
4726
- var MyOrderRepository = class extends OrderRepository {
4727
- create(context, draft) {
4728
- (0, import_assert3.default)(draft.id, "draft.id is missing");
4729
- const cartIdentifier = {
4730
- id: draft.id,
4731
- typeId: "cart"
4732
- };
4733
- return this.createFromCart(context, cartIdentifier);
4734
- }
4735
- };
4736
-
4737
- // src/services/my-order.ts
4738
4665
  var MyOrderService = class extends AbstractService {
4739
- constructor(parent, storage) {
4666
+ constructor(parent, repository) {
4740
4667
  super(parent);
4741
- this.repository = new MyOrderRepository(storage);
4668
+ this.repository = repository;
4742
4669
  }
4743
4670
  getBasePath() {
4744
4671
  return "me";
@@ -4749,13 +4676,262 @@ var MyOrderService = class extends AbstractService {
4749
4676
  this.extraRoutes(router);
4750
4677
  router.get("/orders/", this.get.bind(this));
4751
4678
  router.get("/orders/:id", this.getWithId.bind(this));
4752
- router.delete("/orders/:id", this.deletewithId.bind(this));
4679
+ router.delete("/orders/:id", this.deleteWithId.bind(this));
4753
4680
  router.post("/orders/", this.post.bind(this));
4754
4681
  router.post("/orders/:id", this.postWithId.bind(this));
4755
4682
  parent.use(`/${basePath}`, router);
4756
4683
  }
4757
4684
  };
4758
4685
 
4686
+ // src/services/my-payment.ts
4687
+ var MyPaymentService = class extends AbstractService {
4688
+ constructor(parent, repository) {
4689
+ super(parent);
4690
+ this.repository = repository;
4691
+ }
4692
+ getBasePath() {
4693
+ return "me/payments";
4694
+ }
4695
+ };
4696
+
4697
+ // src/services/order.ts
4698
+ var OrderService = class extends AbstractService {
4699
+ constructor(parent, repository) {
4700
+ super(parent);
4701
+ this.repository = repository;
4702
+ }
4703
+ getBasePath() {
4704
+ return "orders";
4705
+ }
4706
+ extraRoutes(router) {
4707
+ router.post("/import", this.import.bind(this));
4708
+ router.get("/order-number=:orderNumber", this.getWithOrderNumber.bind(this));
4709
+ }
4710
+ import(request, response) {
4711
+ const importDraft = request.body;
4712
+ const resource = this.repository.import(
4713
+ getRepositoryContext(request),
4714
+ importDraft
4715
+ );
4716
+ return response.status(200).send(resource);
4717
+ }
4718
+ getWithOrderNumber(request, response) {
4719
+ const resource = this.repository.getWithOrderNumber(
4720
+ getRepositoryContext(request),
4721
+ request.params.orderNumber,
4722
+ request.query
4723
+ );
4724
+ if (resource) {
4725
+ return response.status(200).send(resource);
4726
+ }
4727
+ return response.status(404).send("Not found");
4728
+ }
4729
+ };
4730
+
4731
+ // src/services/payment.ts
4732
+ var PaymentService = class extends AbstractService {
4733
+ constructor(parent, repository) {
4734
+ super(parent);
4735
+ this.repository = repository;
4736
+ }
4737
+ getBasePath() {
4738
+ return "payments";
4739
+ }
4740
+ };
4741
+
4742
+ // src/services/product.ts
4743
+ var ProductService = class extends AbstractService {
4744
+ constructor(parent, repository) {
4745
+ super(parent);
4746
+ this.repository = repository;
4747
+ }
4748
+ getBasePath() {
4749
+ return "products";
4750
+ }
4751
+ };
4752
+
4753
+ // src/services/product-discount.ts
4754
+ var ProductDiscountService = class extends AbstractService {
4755
+ constructor(parent, repository) {
4756
+ super(parent);
4757
+ this.repository = repository;
4758
+ }
4759
+ getBasePath() {
4760
+ return "product-discounts";
4761
+ }
4762
+ };
4763
+
4764
+ // src/services/product-projection.ts
4765
+ var ProductProjectionService = class extends AbstractService {
4766
+ constructor(parent, repository) {
4767
+ super(parent);
4768
+ this.repository = repository;
4769
+ }
4770
+ getBasePath() {
4771
+ return "product-projections";
4772
+ }
4773
+ extraRoutes(router) {
4774
+ router.get("/search", this.search.bind(this));
4775
+ }
4776
+ search(request, response) {
4777
+ const resource = this.repository.search(
4778
+ getRepositoryContext(request),
4779
+ request.query
4780
+ );
4781
+ return response.status(200).send(resource);
4782
+ }
4783
+ };
4784
+
4785
+ // src/services/product-type.ts
4786
+ var ProductTypeService = class extends AbstractService {
4787
+ constructor(parent, repository) {
4788
+ super(parent);
4789
+ this.repository = repository;
4790
+ }
4791
+ getBasePath() {
4792
+ return "product-types";
4793
+ }
4794
+ };
4795
+
4796
+ // src/services/shipping-method.ts
4797
+ var ShippingMethodService = class extends AbstractService {
4798
+ constructor(parent, repository) {
4799
+ super(parent);
4800
+ this.repository = repository;
4801
+ this.registerRoutes(parent);
4802
+ }
4803
+ getBasePath() {
4804
+ return "shipping-methods";
4805
+ }
4806
+ extraRoutes(parent) {
4807
+ parent.get("/matching-cart", this.get.bind(this));
4808
+ }
4809
+ };
4810
+
4811
+ // src/services/shopping-list.ts
4812
+ var ShoppingListService = class extends AbstractService {
4813
+ constructor(parent, repository) {
4814
+ super(parent);
4815
+ this.repository = repository;
4816
+ }
4817
+ getBasePath() {
4818
+ return "shopping-lists";
4819
+ }
4820
+ };
4821
+
4822
+ // src/services/state.ts
4823
+ var StateService = class extends AbstractService {
4824
+ constructor(parent, repository) {
4825
+ super(parent);
4826
+ this.repository = repository;
4827
+ }
4828
+ getBasePath() {
4829
+ return "states";
4830
+ }
4831
+ };
4832
+
4833
+ // src/services/store.ts
4834
+ var StoreService = class extends AbstractService {
4835
+ constructor(parent, repository) {
4836
+ super(parent);
4837
+ this.repository = repository;
4838
+ }
4839
+ getBasePath() {
4840
+ return "stores";
4841
+ }
4842
+ };
4843
+
4844
+ // src/services/subscription.ts
4845
+ var SubscriptionService = class extends AbstractService {
4846
+ constructor(parent, repository) {
4847
+ super(parent);
4848
+ this.repository = repository;
4849
+ }
4850
+ getBasePath() {
4851
+ return "subscriptions";
4852
+ }
4853
+ };
4854
+
4855
+ // src/services/tax-category.ts
4856
+ var TaxCategoryService = class extends AbstractService {
4857
+ constructor(parent, repository) {
4858
+ super(parent);
4859
+ this.repository = repository;
4860
+ }
4861
+ getBasePath() {
4862
+ return "tax-categories";
4863
+ }
4864
+ };
4865
+
4866
+ // src/services/type.ts
4867
+ var TypeService = class extends AbstractService {
4868
+ constructor(parent, repository) {
4869
+ super(parent);
4870
+ this.repository = repository;
4871
+ }
4872
+ getBasePath() {
4873
+ return "types";
4874
+ }
4875
+ };
4876
+
4877
+ // src/services/zone.ts
4878
+ var ZoneService = class extends AbstractService {
4879
+ constructor(parent, repository) {
4880
+ super(parent);
4881
+ this.repository = repository;
4882
+ }
4883
+ getBasePath() {
4884
+ return "zones";
4885
+ }
4886
+ };
4887
+
4888
+ // src/services/index.ts
4889
+ var createServices = (router, repos) => ({
4890
+ category: new CategoryServices(router, repos["category"]),
4891
+ cart: new CartService(router, repos["cart"], repos["order"]),
4892
+ "cart-discount": new CartDiscountService(router, repos["cart-discount"]),
4893
+ customer: new CustomerService(router, repos["customer"]),
4894
+ channel: new ChannelService(router, repos["channel"]),
4895
+ "customer-group": new CustomerGroupService(router, repos["customer-group"]),
4896
+ "discount-code": new DiscountCodeService(router, repos["discount-code"]),
4897
+ extension: new ExtensionServices(router, repos["extension"]),
4898
+ "inventory-entry": new InventoryEntryService(
4899
+ router,
4900
+ repos["inventory-entry"]
4901
+ ),
4902
+ "key-value-document": new CustomObjectService(
4903
+ router,
4904
+ repos["key-value-document"]
4905
+ ),
4906
+ order: new OrderService(router, repos["order"]),
4907
+ payment: new PaymentService(router, repos["payment"]),
4908
+ "my-cart": new MyCartService(router, repos["my-cart"]),
4909
+ "my-order": new MyOrderService(router, repos["my-order"]),
4910
+ "my-customer": new MyCustomerService(router, repos["my-customer"]),
4911
+ "my-payment": new MyPaymentService(router, repos["my-payment"]),
4912
+ "shipping-method": new ShippingMethodService(
4913
+ router,
4914
+ repos["shipping-method"]
4915
+ ),
4916
+ "product-type": new ProductTypeService(router, repos["product-type"]),
4917
+ product: new ProductService(router, repos["product"]),
4918
+ "product-discount": new ProductDiscountService(
4919
+ router,
4920
+ repos["product-discount"]
4921
+ ),
4922
+ "product-projection": new ProductProjectionService(
4923
+ router,
4924
+ repos["product-projection"]
4925
+ ),
4926
+ "shopping-list": new ShoppingListService(router, repos["shopping-list"]),
4927
+ state: new StateService(router, repos["state"]),
4928
+ store: new StoreService(router, repos["store"]),
4929
+ subscription: new SubscriptionService(router, repos["subscription"]),
4930
+ "tax-category": new TaxCategoryService(router, repos["tax-category"]),
4931
+ type: new TypeService(router, repos["type"]),
4932
+ zone: new ZoneService(router, repos["zone"])
4933
+ });
4934
+
4759
4935
  // src/ctMock.ts
4760
4936
  var DEFAULT_OPTIONS = {
4761
4937
  enableAuthentication: false,
@@ -4769,7 +4945,8 @@ var CommercetoolsMock = class {
4769
4945
  constructor(options = {}) {
4770
4946
  this._nockScopes = { auth: void 0, api: void 0 };
4771
4947
  this.options = { ...DEFAULT_OPTIONS, ...options };
4772
- this._services = {};
4948
+ this._services = null;
4949
+ this._repositories = null;
4773
4950
  this._projectService = void 0;
4774
4951
  this._storage = new InMemoryStorage();
4775
4952
  this._oauth2 = new OAuth2Server({
@@ -4796,20 +4973,23 @@ var CommercetoolsMock = class {
4796
4973
  if (!projectKey && !this.options.defaultProjectKey) {
4797
4974
  throw new Error("No projectKey passed and no default set");
4798
4975
  }
4976
+ if (this._repositories === null) {
4977
+ throw new Error("repositories not initialized yet");
4978
+ }
4799
4979
  return new ProjectAPI(
4800
4980
  projectKey || this.options.defaultProjectKey,
4801
- this._services,
4981
+ this._repositories,
4802
4982
  this._storage
4803
4983
  );
4804
4984
  }
4805
4985
  runServer(port = 3e3, options) {
4806
- const app = this.createApp(options);
4807
- const server = app.listen(port, () => {
4808
- console.log(`Mock server listening at http://localhost:${port}`);
4986
+ const server = this.app.listen(port, () => {
4987
+ console.info(`Mock server listening at http://localhost:${port}`);
4809
4988
  });
4810
4989
  server.keepAliveTimeout = 60 * 1e3;
4811
4990
  }
4812
4991
  createApp(options) {
4992
+ this._repositories = createRepositories(this._storage);
4813
4993
  const app = (0, import_express6.default)();
4814
4994
  const projectRouter = import_express6.default.Router({ mergeParams: true });
4815
4995
  projectRouter.use(import_express6.default.json());
@@ -4828,52 +5008,11 @@ var CommercetoolsMock = class {
4828
5008
  app.use("/:projectKey", projectRouter);
4829
5009
  app.use("/:projectKey/in-store/key=:storeKey", projectRouter);
4830
5010
  }
4831
- this._projectService = new ProjectService(projectRouter, this._storage);
4832
- this._services = {
4833
- category: new CategoryServices(projectRouter, this._storage),
4834
- cart: new CartService(projectRouter, this._storage),
4835
- "cart-discount": new CartDiscountService(projectRouter, this._storage),
4836
- customer: new CustomerService(projectRouter, this._storage),
4837
- channel: new ChannelService(projectRouter, this._storage),
4838
- "customer-group": new CustomerGroupService(projectRouter, this._storage),
4839
- "discount-code": new DiscountCodeService(projectRouter, this._storage),
4840
- extension: new ExtensionServices(projectRouter, this._storage),
4841
- "inventory-entry": new InventoryEntryService(
4842
- projectRouter,
4843
- this._storage
4844
- ),
4845
- "key-value-document": new CustomObjectService(
4846
- projectRouter,
4847
- this._storage
4848
- ),
4849
- order: new OrderService(projectRouter, this._storage),
4850
- payment: new PaymentService(projectRouter, this._storage),
4851
- "my-cart": new MyCartService(projectRouter, this._storage),
4852
- "my-order": new MyOrderService(projectRouter, this._storage),
4853
- "my-customer": new MyCustomerService(projectRouter, this._storage),
4854
- "my-payment": new MyPaymentService(projectRouter, this._storage),
4855
- "shipping-method": new ShippingMethodService(
4856
- projectRouter,
4857
- this._storage
4858
- ),
4859
- "product-type": new ProductTypeService(projectRouter, this._storage),
4860
- product: new ProductService(projectRouter, this._storage),
4861
- "product-discount": new ProductDiscountService(
4862
- projectRouter,
4863
- this._storage
4864
- ),
4865
- "product-projection": new ProductProjectionService(
4866
- projectRouter,
4867
- this._storage
4868
- ),
4869
- "shopping-list": new ShoppingListService(projectRouter, this._storage),
4870
- state: new StateService(projectRouter, this._storage),
4871
- store: new StoreService(projectRouter, this._storage),
4872
- subscription: new SubscriptionService(projectRouter, this._storage),
4873
- "tax-category": new TaxCategoryService(projectRouter, this._storage),
4874
- type: new TypeService(projectRouter, this._storage),
4875
- zone: new ZoneService(projectRouter, this._storage)
4876
- };
5011
+ this._services = createServices(projectRouter, this._repositories);
5012
+ this._projectService = new ProjectService(
5013
+ projectRouter,
5014
+ this._repositories.project
5015
+ );
4877
5016
  app.use((err, req, resp, next) => {
4878
5017
  if (err instanceof CommercetoolsError) {
4879
5018
  return resp.status(err.statusCode).send({