@labdigital/commercetools-mock 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -37,8 +37,8 @@ module.exports = __toCommonJS(src_exports);
37
37
 
38
38
  // src/ctMock.ts
39
39
  var import_express6 = __toESM(require("express"), 1);
40
- var import_supertest = __toESM(require("supertest"), 1);
41
40
  var import_morgan = __toESM(require("morgan"), 1);
41
+ var import_light_my_request = __toESM(require("light-my-request"), 1);
42
42
  var import_node = require("msw/node");
43
43
  var import_msw = require("msw");
44
44
 
@@ -53,10 +53,12 @@ var import_assert = __toESM(require("assert"), 1);
53
53
  var CommercetoolsError = class extends Error {
54
54
  info;
55
55
  statusCode;
56
+ errors;
56
57
  constructor(info, statusCode = 400) {
57
58
  super(info.message);
58
59
  this.info = info;
59
60
  this.statusCode = statusCode || 500;
61
+ this.errors = info.errors ?? [];
60
62
  }
61
63
  };
62
64
 
@@ -101,6 +103,18 @@ var queryParamsValue = (value) => {
101
103
  return void 0;
102
104
  };
103
105
  var cloneObject = (o) => JSON.parse(JSON.stringify(o));
106
+ var mapHeaderType = (outgoingHttpHeaders) => {
107
+ const headersInit = {};
108
+ for (const key in outgoingHttpHeaders) {
109
+ const value = outgoingHttpHeaders[key];
110
+ if (Array.isArray(value)) {
111
+ headersInit[key] = value.join(", ");
112
+ } else if (value !== void 0) {
113
+ headersInit[key] = value.toString();
114
+ }
115
+ }
116
+ return headersInit;
117
+ };
104
118
 
105
119
  // src/lib/expandParser.ts
106
120
  var parseExpandClause = (clause) => {
@@ -1256,6 +1270,16 @@ var OAuth2Store = class {
1256
1270
  this.tokens.push(token);
1257
1271
  return token;
1258
1272
  }
1273
+ getCustomerToken(scope, customerId) {
1274
+ const token = {
1275
+ access_token: (0, import_crypto.randomBytes)(16).toString("base64"),
1276
+ token_type: "Bearer",
1277
+ expires_in: 172800,
1278
+ scope: scope ? `${scope} custome_id:${customerId}` : `customer_id: ${customerId}`
1279
+ };
1280
+ this.tokens.push(token);
1281
+ return token;
1282
+ }
1259
1283
  validateToken(token) {
1260
1284
  if (!this.validate)
1261
1285
  return true;
@@ -1277,16 +1301,36 @@ var getBearerToken = (request) => {
1277
1301
  return void 0;
1278
1302
  };
1279
1303
 
1304
+ // src/lib/password.ts
1305
+ var hashPassword = (clearPassword) => Buffer.from(clearPassword).toString("base64");
1306
+
1280
1307
  // src/oauth/server.ts
1281
1308
  var OAuth2Server = class {
1282
1309
  store;
1310
+ customerRepository;
1283
1311
  constructor(options) {
1284
1312
  this.store = new OAuth2Store(options.validate);
1285
1313
  }
1314
+ setCustomerRepository(repository) {
1315
+ this.customerRepository = repository;
1316
+ }
1286
1317
  createRouter() {
1287
1318
  const router = import_express.default.Router();
1288
1319
  router.use(import_body_parser.default.urlencoded({ extended: true }));
1320
+ router.use(this.validateClientCredentials.bind(this));
1289
1321
  router.post("/token", this.tokenHandler.bind(this));
1322
+ router.post(
1323
+ "/:projectKey/customers/token",
1324
+ this.customerTokenHandler.bind(this)
1325
+ );
1326
+ router.post(
1327
+ "/:projectKey/in-store/key=:storeKey/customers/token",
1328
+ this.inStoreCustomerTokenHandler.bind(this)
1329
+ );
1330
+ router.post(
1331
+ "/:projectKey/anonymous/token",
1332
+ this.anonymousTokenHandler.bind(this)
1333
+ );
1290
1334
  return router;
1291
1335
  }
1292
1336
  createMiddleware() {
@@ -1317,7 +1361,7 @@ var OAuth2Server = class {
1317
1361
  next();
1318
1362
  };
1319
1363
  }
1320
- async tokenHandler(request, response, next) {
1364
+ async validateClientCredentials(request, response, next) {
1321
1365
  const authHeader = request.header("Authorization");
1322
1366
  if (!authHeader) {
1323
1367
  return next(
@@ -1342,6 +1386,13 @@ var OAuth2Server = class {
1342
1386
  )
1343
1387
  );
1344
1388
  }
1389
+ request.credentials = {
1390
+ clientId: credentials.name,
1391
+ clientSecret: credentials.pass
1392
+ };
1393
+ next();
1394
+ }
1395
+ async tokenHandler(request, response, next) {
1345
1396
  const grantType = request.query.grant_type || request.body.grant_type;
1346
1397
  if (!grantType) {
1347
1398
  return next(
@@ -1356,8 +1407,15 @@ var OAuth2Server = class {
1356
1407
  }
1357
1408
  if (grantType === "client_credentials") {
1358
1409
  const token = this.store.getClientToken(
1359
- credentials.name,
1360
- credentials.pass,
1410
+ request.credentials.clientId,
1411
+ request.credentials.clientSecret,
1412
+ request.query.scope?.toString()
1413
+ );
1414
+ return response.status(200).send(token);
1415
+ } else if (grantType === "refresh_token") {
1416
+ const token = this.store.getClientToken(
1417
+ request.credentials.clientId,
1418
+ request.credentials.clientSecret,
1361
1419
  request.query.scope?.toString()
1362
1420
  );
1363
1421
  return response.status(200).send(token);
@@ -1373,6 +1431,69 @@ var OAuth2Server = class {
1373
1431
  );
1374
1432
  }
1375
1433
  }
1434
+ async customerTokenHandler(request, response, next) {
1435
+ const grantType = request.query.grant_type || request.body.grant_type;
1436
+ if (!grantType) {
1437
+ return next(
1438
+ new CommercetoolsError(
1439
+ {
1440
+ code: "invalid_request",
1441
+ message: "Missing required parameter: grant_type."
1442
+ },
1443
+ 400
1444
+ )
1445
+ );
1446
+ }
1447
+ if (grantType === "password") {
1448
+ const username = request.query.username || request.body.username;
1449
+ const password = hashPassword(
1450
+ request.query.password || request.body.password
1451
+ );
1452
+ const scope = request.query.scope?.toString() || request.body.scope?.toString();
1453
+ const result = this.customerRepository.query(
1454
+ { projectKey: request.params.projectKey },
1455
+ {
1456
+ where: [`email = "${username}"`, `password = "${password}"`]
1457
+ }
1458
+ );
1459
+ if (result.count === 0) {
1460
+ return next(
1461
+ new CommercetoolsError(
1462
+ {
1463
+ code: "invalid_customer_account_credentials",
1464
+ message: "Customer account with the given credentials not found."
1465
+ },
1466
+ 400
1467
+ )
1468
+ );
1469
+ }
1470
+ const customer = result.results[0];
1471
+ const token = this.store.getCustomerToken(scope, customer.id);
1472
+ return response.status(200).send(token);
1473
+ }
1474
+ }
1475
+ async inStoreCustomerTokenHandler(request, response, next) {
1476
+ return next(
1477
+ new CommercetoolsError(
1478
+ {
1479
+ code: "invalid_client",
1480
+ message: "Not implemented yet in commercetools-mock"
1481
+ },
1482
+ 401
1483
+ )
1484
+ );
1485
+ }
1486
+ async anonymousTokenHandler(request, response, next) {
1487
+ return next(
1488
+ new CommercetoolsError(
1489
+ {
1490
+ code: "invalid_client",
1491
+ message: "Not implemented yet in commercetools-mock"
1492
+ },
1493
+ 401
1494
+ )
1495
+ );
1496
+ }
1376
1497
  };
1377
1498
 
1378
1499
  // src/projectAPI.ts
@@ -2849,11 +2970,29 @@ var CustomerRepository = class extends AbstractResourceRepository {
2849
2970
  return "customer";
2850
2971
  }
2851
2972
  create(context, draft) {
2973
+ const results = this._storage.query(context.projectKey, this.getTypeId(), {
2974
+ where: [`email="${draft.email.toLocaleLowerCase()}"`]
2975
+ });
2976
+ if (results.count > 0) {
2977
+ throw new CommercetoolsError({
2978
+ code: "CustomerAlreadyExists",
2979
+ statusCode: 400,
2980
+ message: "There is already an existing customer with the provided email.",
2981
+ errors: [
2982
+ {
2983
+ code: "DuplicateField",
2984
+ message: `Customer with email '${draft.email}' already exists.`,
2985
+ duplicateValue: draft.email,
2986
+ field: "email"
2987
+ }
2988
+ ]
2989
+ });
2990
+ }
2852
2991
  const resource = {
2853
2992
  ...getBaseResourceProperties(),
2854
2993
  authenticationMode: draft.authenticationMode || "Password",
2855
- email: draft.email,
2856
- password: draft.password ? Buffer.from(draft.password).toString("base64") : void 0,
2994
+ email: draft.email.toLowerCase(),
2995
+ password: draft.password ? hashPassword(draft.password) : void 0,
2857
2996
  isEmailVerified: draft.isEmailVerified || false,
2858
2997
  addresses: []
2859
2998
  };
@@ -2891,7 +3030,7 @@ var CustomerRepository = class extends AbstractResourceRepository {
2891
3030
  return;
2892
3031
  }
2893
3032
  if (authMode === "Password") {
2894
- resource.password = password ? Buffer.from(password).toString("base64") : void 0;
3033
+ resource.password = password ? hashPassword(password) : void 0;
2895
3034
  return;
2896
3035
  }
2897
3036
  throw new CommercetoolsError(
@@ -6021,7 +6160,7 @@ var MyCustomerService = class extends AbstractService {
6021
6160
  }
6022
6161
  signIn(request, response) {
6023
6162
  const { email, password } = request.body;
6024
- const encodedPassword = Buffer.from(password).toString("base64");
6163
+ const encodedPassword = hashPassword(password);
6025
6164
  const result = this.repository.query(getRepositoryContext(request), {
6026
6165
  where: [`email = "${email}"`, `password = "${encodedPassword}"`]
6027
6166
  });
@@ -6458,6 +6597,7 @@ var CommercetoolsMock = class {
6458
6597
  }
6459
6598
  createApp(options) {
6460
6599
  this._repositories = createRepositories(this._storage);
6600
+ this._oauth2.setCustomerRepository(this._repositories.customer);
6461
6601
  const app = (0, import_express6.default)();
6462
6602
  const projectRouter = import_express6.default.Router({ mergeParams: true });
6463
6603
  projectRouter.use(import_express6.default.json());
@@ -6483,6 +6623,13 @@ var CommercetoolsMock = class {
6483
6623
  );
6484
6624
  app.use((err, req, resp, next) => {
6485
6625
  if (err instanceof CommercetoolsError) {
6626
+ if (err.errors?.length > 0) {
6627
+ return resp.status(err.statusCode).send({
6628
+ statusCode: err.statusCode,
6629
+ message: err.message,
6630
+ errors: err.errors
6631
+ });
6632
+ }
6486
6633
  return resp.status(err.statusCode).send({
6487
6634
  statusCode: err.statusCode,
6488
6635
  message: err.message,
@@ -6506,42 +6653,46 @@ var CommercetoolsMock = class {
6506
6653
  _globalListeners.forEach((listener) => listener.close());
6507
6654
  }
6508
6655
  }
6509
- const app = this.app;
6656
+ const server = this.app;
6510
6657
  this._mswServer = (0, import_node.setupServer)(
6511
6658
  import_msw.http.post(`${this.options.authHost}/oauth/*`, async ({ request }) => {
6512
- const text = await request.text();
6659
+ const body = await request.text();
6513
6660
  const url = new URL(request.url);
6514
- const res = await (0, import_supertest.default)(app).post(url.pathname + "?" + url.searchParams.toString()).set(copyHeaders(request.headers)).send(text);
6515
- return new import_msw.HttpResponse(res.text, {
6516
- status: res.status,
6517
- headers: res.headers
6661
+ const headers = copyHeaders(request.headers);
6662
+ const res = await (0, import_light_my_request.default)(server).post(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
6663
+ return new import_msw.HttpResponse(res.body, {
6664
+ status: res.statusCode,
6665
+ headers: mapHeaderType(res.headers)
6518
6666
  });
6519
6667
  }),
6520
6668
  import_msw.http.get(`${this.options.apiHost}/*`, async ({ request }) => {
6521
6669
  const body = await request.text();
6522
6670
  const url = new URL(request.url);
6523
- const res = await (0, import_supertest.default)(app).get(url.pathname + "?" + url.searchParams.toString()).set(copyHeaders(request.headers)).send(body);
6524
- return new import_msw.HttpResponse(res.text, {
6525
- status: res.status,
6526
- headers: res.headers
6671
+ const headers = copyHeaders(request.headers);
6672
+ const res = await (0, import_light_my_request.default)(server).get(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
6673
+ return new import_msw.HttpResponse(res.body, {
6674
+ status: res.statusCode,
6675
+ headers: mapHeaderType(res.headers)
6527
6676
  });
6528
6677
  }),
6529
6678
  import_msw.http.post(`${this.options.apiHost}/*`, async ({ request }) => {
6530
6679
  const body = await request.text();
6531
6680
  const url = new URL(request.url);
6532
- const res = await (0, import_supertest.default)(app).post(url.pathname + "?" + url.searchParams.toString()).set(copyHeaders(request.headers)).send(body);
6533
- return new import_msw.HttpResponse(res.text, {
6534
- status: res.status,
6535
- headers: res.headers
6681
+ const headers = copyHeaders(request.headers);
6682
+ const res = await (0, import_light_my_request.default)(server).post(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
6683
+ return new import_msw.HttpResponse(res.body, {
6684
+ status: res.statusCode,
6685
+ headers: mapHeaderType(res.headers)
6536
6686
  });
6537
6687
  }),
6538
6688
  import_msw.http.delete(`${this.options.apiHost}/*`, async ({ request }) => {
6539
6689
  const body = await request.text();
6540
6690
  const url = new URL(request.url);
6541
- const res = await (0, import_supertest.default)(app).delete(url.pathname + "?" + url.searchParams.toString()).set(copyHeaders(request.headers)).send(body);
6542
- return new import_msw.HttpResponse(res.text, {
6543
- status: res.status,
6544
- headers: res.headers
6691
+ const headers = copyHeaders(request.headers);
6692
+ const res = await (0, import_light_my_request.default)(server).delete(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
6693
+ return new import_msw.HttpResponse(res.body, {
6694
+ status: res.statusCode,
6695
+ headers: mapHeaderType(res.headers)
6545
6696
  });
6546
6697
  })
6547
6698
  );