@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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/ctMock.ts
2
2
  import express2 from "express";
3
- import supertest from "supertest";
4
3
  import morgan from "morgan";
4
+ import inject from "light-my-request";
5
5
  import { setupServer } from "msw/node";
6
6
  import { http, HttpResponse } from "msw";
7
7
 
@@ -16,10 +16,12 @@ import assert from "assert";
16
16
  var CommercetoolsError = class extends Error {
17
17
  info;
18
18
  statusCode;
19
+ errors;
19
20
  constructor(info, statusCode = 400) {
20
21
  super(info.message);
21
22
  this.info = info;
22
23
  this.statusCode = statusCode || 500;
24
+ this.errors = info.errors ?? [];
23
25
  }
24
26
  };
25
27
 
@@ -64,6 +66,18 @@ var queryParamsValue = (value) => {
64
66
  return void 0;
65
67
  };
66
68
  var cloneObject = (o) => JSON.parse(JSON.stringify(o));
69
+ var mapHeaderType = (outgoingHttpHeaders) => {
70
+ const headersInit = {};
71
+ for (const key in outgoingHttpHeaders) {
72
+ const value = outgoingHttpHeaders[key];
73
+ if (Array.isArray(value)) {
74
+ headersInit[key] = value.join(", ");
75
+ } else if (value !== void 0) {
76
+ headersInit[key] = value.toString();
77
+ }
78
+ }
79
+ return headersInit;
80
+ };
67
81
 
68
82
  // src/lib/expandParser.ts
69
83
  var parseExpandClause = (clause) => {
@@ -1219,6 +1233,16 @@ var OAuth2Store = class {
1219
1233
  this.tokens.push(token);
1220
1234
  return token;
1221
1235
  }
1236
+ getCustomerToken(scope, customerId) {
1237
+ const token = {
1238
+ access_token: randomBytes(16).toString("base64"),
1239
+ token_type: "Bearer",
1240
+ expires_in: 172800,
1241
+ scope: scope ? `${scope} custome_id:${customerId}` : `customer_id: ${customerId}`
1242
+ };
1243
+ this.tokens.push(token);
1244
+ return token;
1245
+ }
1222
1246
  validateToken(token) {
1223
1247
  if (!this.validate)
1224
1248
  return true;
@@ -1240,16 +1264,36 @@ var getBearerToken = (request) => {
1240
1264
  return void 0;
1241
1265
  };
1242
1266
 
1267
+ // src/lib/password.ts
1268
+ var hashPassword = (clearPassword) => Buffer.from(clearPassword).toString("base64");
1269
+
1243
1270
  // src/oauth/server.ts
1244
1271
  var OAuth2Server = class {
1245
1272
  store;
1273
+ customerRepository;
1246
1274
  constructor(options) {
1247
1275
  this.store = new OAuth2Store(options.validate);
1248
1276
  }
1277
+ setCustomerRepository(repository) {
1278
+ this.customerRepository = repository;
1279
+ }
1249
1280
  createRouter() {
1250
1281
  const router = express.Router();
1251
1282
  router.use(bodyParser.urlencoded({ extended: true }));
1283
+ router.use(this.validateClientCredentials.bind(this));
1252
1284
  router.post("/token", this.tokenHandler.bind(this));
1285
+ router.post(
1286
+ "/:projectKey/customers/token",
1287
+ this.customerTokenHandler.bind(this)
1288
+ );
1289
+ router.post(
1290
+ "/:projectKey/in-store/key=:storeKey/customers/token",
1291
+ this.inStoreCustomerTokenHandler.bind(this)
1292
+ );
1293
+ router.post(
1294
+ "/:projectKey/anonymous/token",
1295
+ this.anonymousTokenHandler.bind(this)
1296
+ );
1253
1297
  return router;
1254
1298
  }
1255
1299
  createMiddleware() {
@@ -1280,7 +1324,7 @@ var OAuth2Server = class {
1280
1324
  next();
1281
1325
  };
1282
1326
  }
1283
- async tokenHandler(request, response, next) {
1327
+ async validateClientCredentials(request, response, next) {
1284
1328
  const authHeader = request.header("Authorization");
1285
1329
  if (!authHeader) {
1286
1330
  return next(
@@ -1305,6 +1349,13 @@ var OAuth2Server = class {
1305
1349
  )
1306
1350
  );
1307
1351
  }
1352
+ request.credentials = {
1353
+ clientId: credentials.name,
1354
+ clientSecret: credentials.pass
1355
+ };
1356
+ next();
1357
+ }
1358
+ async tokenHandler(request, response, next) {
1308
1359
  const grantType = request.query.grant_type || request.body.grant_type;
1309
1360
  if (!grantType) {
1310
1361
  return next(
@@ -1319,8 +1370,15 @@ var OAuth2Server = class {
1319
1370
  }
1320
1371
  if (grantType === "client_credentials") {
1321
1372
  const token = this.store.getClientToken(
1322
- credentials.name,
1323
- credentials.pass,
1373
+ request.credentials.clientId,
1374
+ request.credentials.clientSecret,
1375
+ request.query.scope?.toString()
1376
+ );
1377
+ return response.status(200).send(token);
1378
+ } else if (grantType === "refresh_token") {
1379
+ const token = this.store.getClientToken(
1380
+ request.credentials.clientId,
1381
+ request.credentials.clientSecret,
1324
1382
  request.query.scope?.toString()
1325
1383
  );
1326
1384
  return response.status(200).send(token);
@@ -1336,6 +1394,69 @@ var OAuth2Server = class {
1336
1394
  );
1337
1395
  }
1338
1396
  }
1397
+ async customerTokenHandler(request, response, next) {
1398
+ const grantType = request.query.grant_type || request.body.grant_type;
1399
+ if (!grantType) {
1400
+ return next(
1401
+ new CommercetoolsError(
1402
+ {
1403
+ code: "invalid_request",
1404
+ message: "Missing required parameter: grant_type."
1405
+ },
1406
+ 400
1407
+ )
1408
+ );
1409
+ }
1410
+ if (grantType === "password") {
1411
+ const username = request.query.username || request.body.username;
1412
+ const password = hashPassword(
1413
+ request.query.password || request.body.password
1414
+ );
1415
+ const scope = request.query.scope?.toString() || request.body.scope?.toString();
1416
+ const result = this.customerRepository.query(
1417
+ { projectKey: request.params.projectKey },
1418
+ {
1419
+ where: [`email = "${username}"`, `password = "${password}"`]
1420
+ }
1421
+ );
1422
+ if (result.count === 0) {
1423
+ return next(
1424
+ new CommercetoolsError(
1425
+ {
1426
+ code: "invalid_customer_account_credentials",
1427
+ message: "Customer account with the given credentials not found."
1428
+ },
1429
+ 400
1430
+ )
1431
+ );
1432
+ }
1433
+ const customer = result.results[0];
1434
+ const token = this.store.getCustomerToken(scope, customer.id);
1435
+ return response.status(200).send(token);
1436
+ }
1437
+ }
1438
+ async inStoreCustomerTokenHandler(request, response, next) {
1439
+ return next(
1440
+ new CommercetoolsError(
1441
+ {
1442
+ code: "invalid_client",
1443
+ message: "Not implemented yet in commercetools-mock"
1444
+ },
1445
+ 401
1446
+ )
1447
+ );
1448
+ }
1449
+ async anonymousTokenHandler(request, response, next) {
1450
+ return next(
1451
+ new CommercetoolsError(
1452
+ {
1453
+ code: "invalid_client",
1454
+ message: "Not implemented yet in commercetools-mock"
1455
+ },
1456
+ 401
1457
+ )
1458
+ );
1459
+ }
1339
1460
  };
1340
1461
 
1341
1462
  // src/projectAPI.ts
@@ -2812,11 +2933,29 @@ var CustomerRepository = class extends AbstractResourceRepository {
2812
2933
  return "customer";
2813
2934
  }
2814
2935
  create(context, draft) {
2936
+ const results = this._storage.query(context.projectKey, this.getTypeId(), {
2937
+ where: [`email="${draft.email.toLocaleLowerCase()}"`]
2938
+ });
2939
+ if (results.count > 0) {
2940
+ throw new CommercetoolsError({
2941
+ code: "CustomerAlreadyExists",
2942
+ statusCode: 400,
2943
+ message: "There is already an existing customer with the provided email.",
2944
+ errors: [
2945
+ {
2946
+ code: "DuplicateField",
2947
+ message: `Customer with email '${draft.email}' already exists.`,
2948
+ duplicateValue: draft.email,
2949
+ field: "email"
2950
+ }
2951
+ ]
2952
+ });
2953
+ }
2815
2954
  const resource = {
2816
2955
  ...getBaseResourceProperties(),
2817
2956
  authenticationMode: draft.authenticationMode || "Password",
2818
- email: draft.email,
2819
- password: draft.password ? Buffer.from(draft.password).toString("base64") : void 0,
2957
+ email: draft.email.toLowerCase(),
2958
+ password: draft.password ? hashPassword(draft.password) : void 0,
2820
2959
  isEmailVerified: draft.isEmailVerified || false,
2821
2960
  addresses: []
2822
2961
  };
@@ -2854,7 +2993,7 @@ var CustomerRepository = class extends AbstractResourceRepository {
2854
2993
  return;
2855
2994
  }
2856
2995
  if (authMode === "Password") {
2857
- resource.password = password ? Buffer.from(password).toString("base64") : void 0;
2996
+ resource.password = password ? hashPassword(password) : void 0;
2858
2997
  return;
2859
2998
  }
2860
2999
  throw new CommercetoolsError(
@@ -5984,7 +6123,7 @@ var MyCustomerService = class extends AbstractService {
5984
6123
  }
5985
6124
  signIn(request, response) {
5986
6125
  const { email, password } = request.body;
5987
- const encodedPassword = Buffer.from(password).toString("base64");
6126
+ const encodedPassword = hashPassword(password);
5988
6127
  const result = this.repository.query(getRepositoryContext(request), {
5989
6128
  where: [`email = "${email}"`, `password = "${encodedPassword}"`]
5990
6129
  });
@@ -6421,6 +6560,7 @@ var CommercetoolsMock = class {
6421
6560
  }
6422
6561
  createApp(options) {
6423
6562
  this._repositories = createRepositories(this._storage);
6563
+ this._oauth2.setCustomerRepository(this._repositories.customer);
6424
6564
  const app = express2();
6425
6565
  const projectRouter = express2.Router({ mergeParams: true });
6426
6566
  projectRouter.use(express2.json());
@@ -6446,6 +6586,13 @@ var CommercetoolsMock = class {
6446
6586
  );
6447
6587
  app.use((err, req, resp, next) => {
6448
6588
  if (err instanceof CommercetoolsError) {
6589
+ if (err.errors?.length > 0) {
6590
+ return resp.status(err.statusCode).send({
6591
+ statusCode: err.statusCode,
6592
+ message: err.message,
6593
+ errors: err.errors
6594
+ });
6595
+ }
6449
6596
  return resp.status(err.statusCode).send({
6450
6597
  statusCode: err.statusCode,
6451
6598
  message: err.message,
@@ -6469,42 +6616,46 @@ var CommercetoolsMock = class {
6469
6616
  _globalListeners.forEach((listener) => listener.close());
6470
6617
  }
6471
6618
  }
6472
- const app = this.app;
6619
+ const server = this.app;
6473
6620
  this._mswServer = setupServer(
6474
6621
  http.post(`${this.options.authHost}/oauth/*`, async ({ request }) => {
6475
- const text = await request.text();
6622
+ const body = await request.text();
6476
6623
  const url = new URL(request.url);
6477
- const res = await supertest(app).post(url.pathname + "?" + url.searchParams.toString()).set(copyHeaders(request.headers)).send(text);
6478
- return new HttpResponse(res.text, {
6479
- status: res.status,
6480
- headers: res.headers
6624
+ const headers = copyHeaders(request.headers);
6625
+ const res = await inject(server).post(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
6626
+ return new HttpResponse(res.body, {
6627
+ status: res.statusCode,
6628
+ headers: mapHeaderType(res.headers)
6481
6629
  });
6482
6630
  }),
6483
6631
  http.get(`${this.options.apiHost}/*`, async ({ request }) => {
6484
6632
  const body = await request.text();
6485
6633
  const url = new URL(request.url);
6486
- const res = await supertest(app).get(url.pathname + "?" + url.searchParams.toString()).set(copyHeaders(request.headers)).send(body);
6487
- return new HttpResponse(res.text, {
6488
- status: res.status,
6489
- headers: res.headers
6634
+ const headers = copyHeaders(request.headers);
6635
+ const res = await inject(server).get(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
6636
+ return new HttpResponse(res.body, {
6637
+ status: res.statusCode,
6638
+ headers: mapHeaderType(res.headers)
6490
6639
  });
6491
6640
  }),
6492
6641
  http.post(`${this.options.apiHost}/*`, async ({ request }) => {
6493
6642
  const body = await request.text();
6494
6643
  const url = new URL(request.url);
6495
- const res = await supertest(app).post(url.pathname + "?" + url.searchParams.toString()).set(copyHeaders(request.headers)).send(body);
6496
- return new HttpResponse(res.text, {
6497
- status: res.status,
6498
- headers: res.headers
6644
+ const headers = copyHeaders(request.headers);
6645
+ const res = await inject(server).post(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
6646
+ return new HttpResponse(res.body, {
6647
+ status: res.statusCode,
6648
+ headers: mapHeaderType(res.headers)
6499
6649
  });
6500
6650
  }),
6501
6651
  http.delete(`${this.options.apiHost}/*`, async ({ request }) => {
6502
6652
  const body = await request.text();
6503
6653
  const url = new URL(request.url);
6504
- const res = await supertest(app).delete(url.pathname + "?" + url.searchParams.toString()).set(copyHeaders(request.headers)).send(body);
6505
- return new HttpResponse(res.text, {
6506
- status: res.status,
6507
- headers: res.headers
6654
+ const headers = copyHeaders(request.headers);
6655
+ const res = await inject(server).delete(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
6656
+ return new HttpResponse(res.body, {
6657
+ status: res.statusCode,
6658
+ headers: mapHeaderType(res.headers)
6508
6659
  });
6509
6660
  })
6510
6661
  );