@zimic/interceptor 0.17.0-canary.2 → 0.17.0-canary.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/{chunk-TYHJPU5G.js → chunk-MXHLBRPB.js} +521 -61
  2. package/dist/chunk-MXHLBRPB.js.map +1 -0
  3. package/dist/{chunk-3SKHNQLL.mjs → chunk-OGL76CKO.mjs} +510 -60
  4. package/dist/chunk-OGL76CKO.mjs.map +1 -0
  5. package/dist/cli.js +141 -17
  6. package/dist/cli.js.map +1 -1
  7. package/dist/cli.mjs +137 -13
  8. package/dist/cli.mjs.map +1 -1
  9. package/dist/http.d.ts +23 -2
  10. package/dist/http.js +473 -270
  11. package/dist/http.js.map +1 -1
  12. package/dist/http.mjs +473 -270
  13. package/dist/http.mjs.map +1 -1
  14. package/dist/scripts/postinstall.js +6 -6
  15. package/dist/scripts/postinstall.js.map +1 -1
  16. package/dist/scripts/postinstall.mjs +5 -5
  17. package/dist/scripts/postinstall.mjs.map +1 -1
  18. package/dist/server.d.ts +16 -0
  19. package/dist/server.js +6 -6
  20. package/dist/server.mjs +1 -1
  21. package/package.json +12 -11
  22. package/src/cli/browser/init.ts +5 -6
  23. package/src/cli/cli.ts +140 -55
  24. package/src/cli/server/start.ts +22 -7
  25. package/src/cli/server/token/create.ts +33 -0
  26. package/src/cli/server/token/list.ts +23 -0
  27. package/src/cli/server/token/remove.ts +22 -0
  28. package/src/http/interceptor/HttpInterceptorClient.ts +49 -27
  29. package/src/http/interceptor/HttpInterceptorStore.ts +25 -9
  30. package/src/http/interceptor/LocalHttpInterceptor.ts +6 -3
  31. package/src/http/interceptor/RemoteHttpInterceptor.ts +41 -5
  32. package/src/http/interceptor/errors/RunningHttpInterceptorError.ts +1 -1
  33. package/src/http/interceptor/types/options.ts +15 -0
  34. package/src/http/interceptor/types/public.ts +11 -3
  35. package/src/http/interceptorWorker/HttpInterceptorWorker.ts +14 -16
  36. package/src/http/interceptorWorker/RemoteHttpInterceptorWorker.ts +17 -12
  37. package/src/http/interceptorWorker/types/options.ts +1 -0
  38. package/src/http/requestHandler/errors/TimesCheckError.ts +1 -1
  39. package/src/server/InterceptorServer.ts +52 -8
  40. package/src/server/constants.ts +1 -1
  41. package/src/server/errors/InvalidInterceptorTokenError.ts +13 -0
  42. package/src/server/errors/InvalidInterceptorTokenFileError.ts +13 -0
  43. package/src/server/errors/InvalidInterceptorTokenValueError.ts +13 -0
  44. package/src/server/types/options.ts +9 -0
  45. package/src/server/types/public.ts +9 -0
  46. package/src/server/types/schema.ts +4 -4
  47. package/src/server/utils/auth.ts +304 -0
  48. package/src/server/utils/fetch.ts +3 -1
  49. package/src/utils/data.ts +13 -0
  50. package/src/utils/files.ts +14 -0
  51. package/src/utils/{console.ts → logging.ts} +5 -7
  52. package/src/utils/webSocket.ts +57 -11
  53. package/src/webSocket/WebSocketClient.ts +11 -5
  54. package/src/webSocket/WebSocketHandler.ts +72 -51
  55. package/src/webSocket/WebSocketServer.ts +25 -4
  56. package/src/webSocket/constants.ts +2 -0
  57. package/src/webSocket/errors/UnauthorizedWebSocketConnectionError.ts +11 -0
  58. package/src/webSocket/types.ts +49 -52
  59. package/dist/chunk-3SKHNQLL.mjs.map +0 -1
  60. package/dist/chunk-TYHJPU5G.js.map +0 -1
@@ -1,32 +1,32 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkWCQVDF3K_js = require('../chunk-WCQVDF3K.js');
4
- var filesystem = require('fs/promises');
4
+ var fs = require('fs');
5
5
  var path = require('path');
6
6
 
7
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
8
 
9
- var filesystem__default = /*#__PURE__*/_interopDefault(filesystem);
9
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
10
10
  var path__default = /*#__PURE__*/_interopDefault(path);
11
11
 
12
12
  var MSW_ROOT_DIRECTORY = path__default.default.join(chunkWCQVDF3K_js.__require.resolve("msw"), "..", "..", "..");
13
13
  var MSW_PACKAGE_PATH = path__default.default.join(MSW_ROOT_DIRECTORY, "package.json");
14
14
  var MSW_BROWSER_DIRECTORY = path__default.default.join(MSW_ROOT_DIRECTORY, "lib", "browser");
15
15
  async function patchMSWExports() {
16
- const mswPackageContentAsString = await filesystem__default.default.readFile(MSW_PACKAGE_PATH, "utf-8");
16
+ const mswPackageContentAsString = await fs__default.default.promises.readFile(MSW_PACKAGE_PATH, "utf-8");
17
17
  const mswPackageContent = JSON.parse(mswPackageContentAsString);
18
18
  const browserExports = mswPackageContent.exports["./browser"];
19
19
  const nodeExports = mswPackageContent.exports["./node"];
20
20
  browserExports.node = nodeExports.node;
21
21
  nodeExports.browser = browserExports.browser;
22
22
  const patchedMSWPackageContentAsString = JSON.stringify(mswPackageContent, null, 2);
23
- await filesystem__default.default.writeFile(MSW_PACKAGE_PATH, patchedMSWPackageContentAsString);
23
+ await fs__default.default.promises.writeFile(MSW_PACKAGE_PATH, patchedMSWPackageContentAsString);
24
24
  }
25
25
  chunkWCQVDF3K_js.__name(patchMSWExports, "patchMSWExports");
26
26
  async function patchMSWBrowserEntry() {
27
27
  for (const indexFileName of ["index.js", "index.mjs"]) {
28
28
  const mswBrowserPath = path__default.default.join(MSW_BROWSER_DIRECTORY, indexFileName);
29
- const mswBrowserContent = await filesystem__default.default.readFile(mswBrowserPath, "utf-8");
29
+ const mswBrowserContent = await fs__default.default.promises.readFile(mswBrowserPath, "utf-8");
30
30
  const patchedMSWBrowserContent = mswBrowserContent.replace(
31
31
  `if (responseJson.type?.includes("opaque")) {
32
32
  return;
@@ -35,7 +35,7 @@ async function patchMSWBrowserEntry() {
35
35
  return;
36
36
  }`
37
37
  );
38
- await filesystem__default.default.writeFile(mswBrowserPath, patchedMSWBrowserContent);
38
+ await fs__default.default.promises.writeFile(mswBrowserPath, patchedMSWBrowserContent);
39
39
  }
40
40
  }
41
41
  chunkWCQVDF3K_js.__name(patchMSWBrowserEntry, "patchMSWBrowserEntry");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../scripts/postinstall.ts"],"names":["path","__require","filesystem","__name"],"mappings":";;;;;;;;;;;AAQa,IAAA,kBAAA,GAAqBA,sBAAK,IAAK,CAAAC,0BAAA,CAAQ,QAAQ,KAAK,CAAA,EAAG,IAAM,EAAA,IAAA,EAAM,IAAI;AAC7E,IAAM,gBAAmB,GAAAD,qBAAA,CAAK,IAAK,CAAA,kBAAA,EAAoB,cAAc;AACrE,IAAM,qBAAwB,GAAAA,qBAAA,CAAK,IAAK,CAAA,kBAAA,EAAoB,OAAO,SAAS;AAEnF,eAAe,eAAkB,GAAA;AAC/B,EAAA,MAAM,yBAA4B,GAAA,MAAME,2BAAW,CAAA,QAAA,CAAS,kBAAkB,OAAO,CAAA;AACrF,EAAM,MAAA,iBAAA,GAAoB,IAAK,CAAA,KAAA,CAAM,yBAAyB,CAAA;AAE9D,EAAM,MAAA,cAAA,GAAiB,iBAAkB,CAAA,OAAA,CAAQ,WAAW,CAAA;AAK5D,EAAM,MAAA,WAAA,GAAc,iBAAkB,CAAA,OAAA,CAAQ,QAAQ,CAAA;AAKtD,EAAA,cAAA,CAAe,OAAO,WAAY,CAAA,IAAA;AAClC,EAAA,WAAA,CAAY,UAAU,cAAe,CAAA,OAAA;AAErC,EAAA,MAAM,gCAAmC,GAAA,IAAA,CAAK,SAAU,CAAA,iBAAA,EAAmB,MAAM,CAAC,CAAA;AAClF,EAAM,MAAAA,2BAAA,CAAW,SAAU,CAAA,gBAAA,EAAkB,gCAAgC,CAAA;AAC/E;AAnBeC,uBAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAsBf,eAAe,oBAAuB,GAAA;AACpC,EAAA,KAAA,MAAW,aAAiB,IAAA,CAAC,UAAY,EAAA,WAAW,CAAG,EAAA;AACrD,IAAA,MAAM,cAAiB,GAAAH,qBAAA,CAAK,IAAK,CAAA,qBAAA,EAAuB,aAAa,CAAA;AACrE,IAAA,MAAM,iBAAoB,GAAA,MAAME,2BAAW,CAAA,QAAA,CAAS,gBAAgB,OAAO,CAAA;AAE3E,IAAA,MAAM,2BAA2B,iBAAkB,CAAA,OAAA;AAAA,MACjD,CAAA;AAAA;AAAA,KAAA,CAAA;AAAA,MAIA,CAAA;AAAA;AAAA,KAAA;AAAA,KAGF;AAEA,IAAM,MAAAA,2BAAA,CAAW,SAAU,CAAA,cAAA,EAAgB,wBAAwB,CAAA;AAAA;AAEvE;AAjBeC,uBAAA,CAAA,oBAAA,EAAA,sBAAA,CAAA;AAmBf,eAAe,WAAc,GAAA;AAC3B,EAAA,MAAM,eAAgB,EAAA;AACtB,EAAA,MAAM,oBAAqB,EAAA;AAC7B;AAHeA,uBAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAKR,IAAM,qBAAqB,WAAY","file":"postinstall.js","sourcesContent":["import { Override } from '@zimic/utils/types';\nimport filesystem from 'fs/promises';\nimport type mswPackage from 'msw/package.json';\nimport path from 'path';\n\nexport type MSWPackage = typeof mswPackage;\nexport type MSWExports = MSWPackage['exports'];\n\nexport const MSW_ROOT_DIRECTORY = path.join(require.resolve('msw'), '..', '..', '..');\nexport const MSW_PACKAGE_PATH = path.join(MSW_ROOT_DIRECTORY, 'package.json');\nexport const MSW_BROWSER_DIRECTORY = path.join(MSW_ROOT_DIRECTORY, 'lib', 'browser');\n\nasync function patchMSWExports() {\n const mswPackageContentAsString = await filesystem.readFile(MSW_PACKAGE_PATH, 'utf-8');\n const mswPackageContent = JSON.parse(mswPackageContentAsString) as MSWPackage;\n\n const browserExports = mswPackageContent.exports['./browser'] as Override<\n MSWExports['./browser'],\n { node: MSWExports['./node']['node'] | string | null }\n >;\n\n const nodeExports = mswPackageContent.exports['./node'] as Override<\n MSWExports['./node'],\n { browser: MSWExports['./browser']['browser'] | string | null }\n >;\n\n browserExports.node = nodeExports.node;\n nodeExports.browser = browserExports.browser;\n\n const patchedMSWPackageContentAsString = JSON.stringify(mswPackageContent, null, 2);\n await filesystem.writeFile(MSW_PACKAGE_PATH, patchedMSWPackageContentAsString);\n}\n\n// This is a temporary workaround. Once https://github.com/mswjs/msw/issues/2146 is fixed, we'll be able to remove it.\nasync function patchMSWBrowserEntry() {\n for (const indexFileName of ['index.js', 'index.mjs']) {\n const mswBrowserPath = path.join(MSW_BROWSER_DIRECTORY, indexFileName);\n const mswBrowserContent = await filesystem.readFile(mswBrowserPath, 'utf-8');\n\n const patchedMSWBrowserContent = mswBrowserContent.replace(\n `if (responseJson.type?.includes(\"opaque\")) {\n return;\n }`,\n\n `if (!request || responseJson.type?.includes(\"opaque\")) {\n return;\n }`,\n );\n\n await filesystem.writeFile(mswBrowserPath, patchedMSWBrowserContent);\n }\n}\n\nasync function postinstall() {\n await patchMSWExports();\n await patchMSWBrowserEntry();\n}\n\nexport const postinstallPromise = postinstall();\n"]}
1
+ {"version":3,"sources":["../../scripts/postinstall.ts"],"names":["path","__require","fs","__name"],"mappings":";;;;;;;;;;;AAQa,IAAA,kBAAA,GAAqBA,sBAAK,IAAK,CAAAC,0BAAA,CAAQ,QAAQ,KAAK,CAAA,EAAG,IAAM,EAAA,IAAA,EAAM,IAAI;AAC7E,IAAM,gBAAmB,GAAAD,qBAAA,CAAK,IAAK,CAAA,kBAAA,EAAoB,cAAc;AACrE,IAAM,qBAAwB,GAAAA,qBAAA,CAAK,IAAK,CAAA,kBAAA,EAAoB,OAAO,SAAS;AAEnF,eAAe,eAAkB,GAAA;AAC/B,EAAA,MAAM,4BAA4B,MAAME,mBAAA,CAAG,QAAS,CAAA,QAAA,CAAS,kBAAkB,OAAO,CAAA;AACtF,EAAM,MAAA,iBAAA,GAAoB,IAAK,CAAA,KAAA,CAAM,yBAAyB,CAAA;AAE9D,EAAM,MAAA,cAAA,GAAiB,iBAAkB,CAAA,OAAA,CAAQ,WAAW,CAAA;AAK5D,EAAM,MAAA,WAAA,GAAc,iBAAkB,CAAA,OAAA,CAAQ,QAAQ,CAAA;AAKtD,EAAA,cAAA,CAAe,OAAO,WAAY,CAAA,IAAA;AAClC,EAAA,WAAA,CAAY,UAAU,cAAe,CAAA,OAAA;AAErC,EAAA,MAAM,gCAAmC,GAAA,IAAA,CAAK,SAAU,CAAA,iBAAA,EAAmB,MAAM,CAAC,CAAA;AAClF,EAAA,MAAMA,mBAAG,CAAA,QAAA,CAAS,SAAU,CAAA,gBAAA,EAAkB,gCAAgC,CAAA;AAChF;AAnBeC,uBAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAsBf,eAAe,oBAAuB,GAAA;AACpC,EAAA,KAAA,MAAW,aAAiB,IAAA,CAAC,UAAY,EAAA,WAAW,CAAG,EAAA;AACrD,IAAA,MAAM,cAAiB,GAAAH,qBAAA,CAAK,IAAK,CAAA,qBAAA,EAAuB,aAAa,CAAA;AACrE,IAAA,MAAM,oBAAoB,MAAME,mBAAA,CAAG,QAAS,CAAA,QAAA,CAAS,gBAAgB,OAAO,CAAA;AAE5E,IAAA,MAAM,2BAA2B,iBAAkB,CAAA,OAAA;AAAA,MACjD,CAAA;AAAA;AAAA,KAAA,CAAA;AAAA,MAIA,CAAA;AAAA;AAAA,KAAA;AAAA,KAGF;AAEA,IAAA,MAAMA,mBAAG,CAAA,QAAA,CAAS,SAAU,CAAA,cAAA,EAAgB,wBAAwB,CAAA;AAAA;AAExE;AAjBeC,uBAAA,CAAA,oBAAA,EAAA,sBAAA,CAAA;AAmBf,eAAe,WAAc,GAAA;AAC3B,EAAA,MAAM,eAAgB,EAAA;AACtB,EAAA,MAAM,oBAAqB,EAAA;AAC7B;AAHeA,uBAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAKR,IAAM,qBAAqB,WAAY","file":"postinstall.js","sourcesContent":["import { Override } from '@zimic/utils/types';\nimport fs from 'fs';\nimport type mswPackage from 'msw/package.json';\nimport path from 'path';\n\nexport type MSWPackage = typeof mswPackage;\nexport type MSWExports = MSWPackage['exports'];\n\nexport const MSW_ROOT_DIRECTORY = path.join(require.resolve('msw'), '..', '..', '..');\nexport const MSW_PACKAGE_PATH = path.join(MSW_ROOT_DIRECTORY, 'package.json');\nexport const MSW_BROWSER_DIRECTORY = path.join(MSW_ROOT_DIRECTORY, 'lib', 'browser');\n\nasync function patchMSWExports() {\n const mswPackageContentAsString = await fs.promises.readFile(MSW_PACKAGE_PATH, 'utf-8');\n const mswPackageContent = JSON.parse(mswPackageContentAsString) as MSWPackage;\n\n const browserExports = mswPackageContent.exports['./browser'] as Override<\n MSWExports['./browser'],\n { node: MSWExports['./node']['node'] | string | null }\n >;\n\n const nodeExports = mswPackageContent.exports['./node'] as Override<\n MSWExports['./node'],\n { browser: MSWExports['./browser']['browser'] | string | null }\n >;\n\n browserExports.node = nodeExports.node;\n nodeExports.browser = browserExports.browser;\n\n const patchedMSWPackageContentAsString = JSON.stringify(mswPackageContent, null, 2);\n await fs.promises.writeFile(MSW_PACKAGE_PATH, patchedMSWPackageContentAsString);\n}\n\n// This is a temporary workaround. Once https://github.com/mswjs/msw/issues/2146 is fixed, we'll be able to remove it.\nasync function patchMSWBrowserEntry() {\n for (const indexFileName of ['index.js', 'index.mjs']) {\n const mswBrowserPath = path.join(MSW_BROWSER_DIRECTORY, indexFileName);\n const mswBrowserContent = await fs.promises.readFile(mswBrowserPath, 'utf-8');\n\n const patchedMSWBrowserContent = mswBrowserContent.replace(\n `if (responseJson.type?.includes(\"opaque\")) {\n return;\n }`,\n\n `if (!request || responseJson.type?.includes(\"opaque\")) {\n return;\n }`,\n );\n\n await fs.promises.writeFile(mswBrowserPath, patchedMSWBrowserContent);\n }\n}\n\nasync function postinstall() {\n await patchMSWExports();\n await patchMSWBrowserEntry();\n}\n\nexport const postinstallPromise = postinstall();\n"]}
@@ -1,25 +1,25 @@
1
1
  import { __require, __name } from '../chunk-CGILA3WO.mjs';
2
- import filesystem from 'fs/promises';
2
+ import fs from 'fs';
3
3
  import path from 'path';
4
4
 
5
5
  var MSW_ROOT_DIRECTORY = path.join(__require.resolve("msw"), "..", "..", "..");
6
6
  var MSW_PACKAGE_PATH = path.join(MSW_ROOT_DIRECTORY, "package.json");
7
7
  var MSW_BROWSER_DIRECTORY = path.join(MSW_ROOT_DIRECTORY, "lib", "browser");
8
8
  async function patchMSWExports() {
9
- const mswPackageContentAsString = await filesystem.readFile(MSW_PACKAGE_PATH, "utf-8");
9
+ const mswPackageContentAsString = await fs.promises.readFile(MSW_PACKAGE_PATH, "utf-8");
10
10
  const mswPackageContent = JSON.parse(mswPackageContentAsString);
11
11
  const browserExports = mswPackageContent.exports["./browser"];
12
12
  const nodeExports = mswPackageContent.exports["./node"];
13
13
  browserExports.node = nodeExports.node;
14
14
  nodeExports.browser = browserExports.browser;
15
15
  const patchedMSWPackageContentAsString = JSON.stringify(mswPackageContent, null, 2);
16
- await filesystem.writeFile(MSW_PACKAGE_PATH, patchedMSWPackageContentAsString);
16
+ await fs.promises.writeFile(MSW_PACKAGE_PATH, patchedMSWPackageContentAsString);
17
17
  }
18
18
  __name(patchMSWExports, "patchMSWExports");
19
19
  async function patchMSWBrowserEntry() {
20
20
  for (const indexFileName of ["index.js", "index.mjs"]) {
21
21
  const mswBrowserPath = path.join(MSW_BROWSER_DIRECTORY, indexFileName);
22
- const mswBrowserContent = await filesystem.readFile(mswBrowserPath, "utf-8");
22
+ const mswBrowserContent = await fs.promises.readFile(mswBrowserPath, "utf-8");
23
23
  const patchedMSWBrowserContent = mswBrowserContent.replace(
24
24
  `if (responseJson.type?.includes("opaque")) {
25
25
  return;
@@ -28,7 +28,7 @@ async function patchMSWBrowserEntry() {
28
28
  return;
29
29
  }`
30
30
  );
31
- await filesystem.writeFile(mswBrowserPath, patchedMSWBrowserContent);
31
+ await fs.promises.writeFile(mswBrowserPath, patchedMSWBrowserContent);
32
32
  }
33
33
  }
34
34
  __name(patchMSWBrowserEntry, "patchMSWBrowserEntry");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../scripts/postinstall.ts"],"names":[],"mappings":";;;;AAQa,IAAA,kBAAA,GAAqB,KAAK,IAAK,CAAA,SAAA,CAAQ,QAAQ,KAAK,CAAA,EAAG,IAAM,EAAA,IAAA,EAAM,IAAI;AAC7E,IAAM,gBAAmB,GAAA,IAAA,CAAK,IAAK,CAAA,kBAAA,EAAoB,cAAc;AACrE,IAAM,qBAAwB,GAAA,IAAA,CAAK,IAAK,CAAA,kBAAA,EAAoB,OAAO,SAAS;AAEnF,eAAe,eAAkB,GAAA;AAC/B,EAAA,MAAM,yBAA4B,GAAA,MAAM,UAAW,CAAA,QAAA,CAAS,kBAAkB,OAAO,CAAA;AACrF,EAAM,MAAA,iBAAA,GAAoB,IAAK,CAAA,KAAA,CAAM,yBAAyB,CAAA;AAE9D,EAAM,MAAA,cAAA,GAAiB,iBAAkB,CAAA,OAAA,CAAQ,WAAW,CAAA;AAK5D,EAAM,MAAA,WAAA,GAAc,iBAAkB,CAAA,OAAA,CAAQ,QAAQ,CAAA;AAKtD,EAAA,cAAA,CAAe,OAAO,WAAY,CAAA,IAAA;AAClC,EAAA,WAAA,CAAY,UAAU,cAAe,CAAA,OAAA;AAErC,EAAA,MAAM,gCAAmC,GAAA,IAAA,CAAK,SAAU,CAAA,iBAAA,EAAmB,MAAM,CAAC,CAAA;AAClF,EAAM,MAAA,UAAA,CAAW,SAAU,CAAA,gBAAA,EAAkB,gCAAgC,CAAA;AAC/E;AAnBe,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAsBf,eAAe,oBAAuB,GAAA;AACpC,EAAA,KAAA,MAAW,aAAiB,IAAA,CAAC,UAAY,EAAA,WAAW,CAAG,EAAA;AACrD,IAAA,MAAM,cAAiB,GAAA,IAAA,CAAK,IAAK,CAAA,qBAAA,EAAuB,aAAa,CAAA;AACrE,IAAA,MAAM,iBAAoB,GAAA,MAAM,UAAW,CAAA,QAAA,CAAS,gBAAgB,OAAO,CAAA;AAE3E,IAAA,MAAM,2BAA2B,iBAAkB,CAAA,OAAA;AAAA,MACjD,CAAA;AAAA;AAAA,KAAA,CAAA;AAAA,MAIA,CAAA;AAAA;AAAA,KAAA;AAAA,KAGF;AAEA,IAAM,MAAA,UAAA,CAAW,SAAU,CAAA,cAAA,EAAgB,wBAAwB,CAAA;AAAA;AAEvE;AAjBe,MAAA,CAAA,oBAAA,EAAA,sBAAA,CAAA;AAmBf,eAAe,WAAc,GAAA;AAC3B,EAAA,MAAM,eAAgB,EAAA;AACtB,EAAA,MAAM,oBAAqB,EAAA;AAC7B;AAHe,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAKR,IAAM,qBAAqB,WAAY","file":"postinstall.mjs","sourcesContent":["import { Override } from '@zimic/utils/types';\nimport filesystem from 'fs/promises';\nimport type mswPackage from 'msw/package.json';\nimport path from 'path';\n\nexport type MSWPackage = typeof mswPackage;\nexport type MSWExports = MSWPackage['exports'];\n\nexport const MSW_ROOT_DIRECTORY = path.join(require.resolve('msw'), '..', '..', '..');\nexport const MSW_PACKAGE_PATH = path.join(MSW_ROOT_DIRECTORY, 'package.json');\nexport const MSW_BROWSER_DIRECTORY = path.join(MSW_ROOT_DIRECTORY, 'lib', 'browser');\n\nasync function patchMSWExports() {\n const mswPackageContentAsString = await filesystem.readFile(MSW_PACKAGE_PATH, 'utf-8');\n const mswPackageContent = JSON.parse(mswPackageContentAsString) as MSWPackage;\n\n const browserExports = mswPackageContent.exports['./browser'] as Override<\n MSWExports['./browser'],\n { node: MSWExports['./node']['node'] | string | null }\n >;\n\n const nodeExports = mswPackageContent.exports['./node'] as Override<\n MSWExports['./node'],\n { browser: MSWExports['./browser']['browser'] | string | null }\n >;\n\n browserExports.node = nodeExports.node;\n nodeExports.browser = browserExports.browser;\n\n const patchedMSWPackageContentAsString = JSON.stringify(mswPackageContent, null, 2);\n await filesystem.writeFile(MSW_PACKAGE_PATH, patchedMSWPackageContentAsString);\n}\n\n// This is a temporary workaround. Once https://github.com/mswjs/msw/issues/2146 is fixed, we'll be able to remove it.\nasync function patchMSWBrowserEntry() {\n for (const indexFileName of ['index.js', 'index.mjs']) {\n const mswBrowserPath = path.join(MSW_BROWSER_DIRECTORY, indexFileName);\n const mswBrowserContent = await filesystem.readFile(mswBrowserPath, 'utf-8');\n\n const patchedMSWBrowserContent = mswBrowserContent.replace(\n `if (responseJson.type?.includes(\"opaque\")) {\n return;\n }`,\n\n `if (!request || responseJson.type?.includes(\"opaque\")) {\n return;\n }`,\n );\n\n await filesystem.writeFile(mswBrowserPath, patchedMSWBrowserContent);\n }\n}\n\nasync function postinstall() {\n await patchMSWExports();\n await patchMSWBrowserEntry();\n}\n\nexport const postinstallPromise = postinstall();\n"]}
1
+ {"version":3,"sources":["../../scripts/postinstall.ts"],"names":[],"mappings":";;;;AAQa,IAAA,kBAAA,GAAqB,KAAK,IAAK,CAAA,SAAA,CAAQ,QAAQ,KAAK,CAAA,EAAG,IAAM,EAAA,IAAA,EAAM,IAAI;AAC7E,IAAM,gBAAmB,GAAA,IAAA,CAAK,IAAK,CAAA,kBAAA,EAAoB,cAAc;AACrE,IAAM,qBAAwB,GAAA,IAAA,CAAK,IAAK,CAAA,kBAAA,EAAoB,OAAO,SAAS;AAEnF,eAAe,eAAkB,GAAA;AAC/B,EAAA,MAAM,4BAA4B,MAAM,EAAA,CAAG,QAAS,CAAA,QAAA,CAAS,kBAAkB,OAAO,CAAA;AACtF,EAAM,MAAA,iBAAA,GAAoB,IAAK,CAAA,KAAA,CAAM,yBAAyB,CAAA;AAE9D,EAAM,MAAA,cAAA,GAAiB,iBAAkB,CAAA,OAAA,CAAQ,WAAW,CAAA;AAK5D,EAAM,MAAA,WAAA,GAAc,iBAAkB,CAAA,OAAA,CAAQ,QAAQ,CAAA;AAKtD,EAAA,cAAA,CAAe,OAAO,WAAY,CAAA,IAAA;AAClC,EAAA,WAAA,CAAY,UAAU,cAAe,CAAA,OAAA;AAErC,EAAA,MAAM,gCAAmC,GAAA,IAAA,CAAK,SAAU,CAAA,iBAAA,EAAmB,MAAM,CAAC,CAAA;AAClF,EAAA,MAAM,EAAG,CAAA,QAAA,CAAS,SAAU,CAAA,gBAAA,EAAkB,gCAAgC,CAAA;AAChF;AAnBe,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAsBf,eAAe,oBAAuB,GAAA;AACpC,EAAA,KAAA,MAAW,aAAiB,IAAA,CAAC,UAAY,EAAA,WAAW,CAAG,EAAA;AACrD,IAAA,MAAM,cAAiB,GAAA,IAAA,CAAK,IAAK,CAAA,qBAAA,EAAuB,aAAa,CAAA;AACrE,IAAA,MAAM,oBAAoB,MAAM,EAAA,CAAG,QAAS,CAAA,QAAA,CAAS,gBAAgB,OAAO,CAAA;AAE5E,IAAA,MAAM,2BAA2B,iBAAkB,CAAA,OAAA;AAAA,MACjD,CAAA;AAAA;AAAA,KAAA,CAAA;AAAA,MAIA,CAAA;AAAA;AAAA,KAAA;AAAA,KAGF;AAEA,IAAA,MAAM,EAAG,CAAA,QAAA,CAAS,SAAU,CAAA,cAAA,EAAgB,wBAAwB,CAAA;AAAA;AAExE;AAjBe,MAAA,CAAA,oBAAA,EAAA,sBAAA,CAAA;AAmBf,eAAe,WAAc,GAAA;AAC3B,EAAA,MAAM,eAAgB,EAAA;AACtB,EAAA,MAAM,oBAAqB,EAAA;AAC7B;AAHe,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAKR,IAAM,qBAAqB,WAAY","file":"postinstall.mjs","sourcesContent":["import { Override } from '@zimic/utils/types';\nimport fs from 'fs';\nimport type mswPackage from 'msw/package.json';\nimport path from 'path';\n\nexport type MSWPackage = typeof mswPackage;\nexport type MSWExports = MSWPackage['exports'];\n\nexport const MSW_ROOT_DIRECTORY = path.join(require.resolve('msw'), '..', '..', '..');\nexport const MSW_PACKAGE_PATH = path.join(MSW_ROOT_DIRECTORY, 'package.json');\nexport const MSW_BROWSER_DIRECTORY = path.join(MSW_ROOT_DIRECTORY, 'lib', 'browser');\n\nasync function patchMSWExports() {\n const mswPackageContentAsString = await fs.promises.readFile(MSW_PACKAGE_PATH, 'utf-8');\n const mswPackageContent = JSON.parse(mswPackageContentAsString) as MSWPackage;\n\n const browserExports = mswPackageContent.exports['./browser'] as Override<\n MSWExports['./browser'],\n { node: MSWExports['./node']['node'] | string | null }\n >;\n\n const nodeExports = mswPackageContent.exports['./node'] as Override<\n MSWExports['./node'],\n { browser: MSWExports['./browser']['browser'] | string | null }\n >;\n\n browserExports.node = nodeExports.node;\n nodeExports.browser = browserExports.browser;\n\n const patchedMSWPackageContentAsString = JSON.stringify(mswPackageContent, null, 2);\n await fs.promises.writeFile(MSW_PACKAGE_PATH, patchedMSWPackageContentAsString);\n}\n\n// This is a temporary workaround. Once https://github.com/mswjs/msw/issues/2146 is fixed, we'll be able to remove it.\nasync function patchMSWBrowserEntry() {\n for (const indexFileName of ['index.js', 'index.mjs']) {\n const mswBrowserPath = path.join(MSW_BROWSER_DIRECTORY, indexFileName);\n const mswBrowserContent = await fs.promises.readFile(mswBrowserPath, 'utf-8');\n\n const patchedMSWBrowserContent = mswBrowserContent.replace(\n `if (responseJson.type?.includes(\"opaque\")) {\n return;\n }`,\n\n `if (!request || responseJson.type?.includes(\"opaque\")) {\n return;\n }`,\n );\n\n await fs.promises.writeFile(mswBrowserPath, patchedMSWBrowserContent);\n }\n}\n\nasync function postinstall() {\n await patchMSWExports();\n await patchMSWBrowserEntry();\n}\n\nexport const postinstallPromise = postinstall();\n"]}
package/dist/server.d.ts CHANGED
@@ -33,6 +33,14 @@ interface InterceptorServerOptions {
33
33
  * @default true
34
34
  */
35
35
  logUnhandledRequests?: boolean;
36
+ /**
37
+ * The directory where the authorized interceptor authentication tokens are saved. If provided, only remote
38
+ * interceptors bearing a valid token will be accepted. This option is essential if you are exposing your interceptor
39
+ * server publicly. For local development and testing, though, `--tokens-dir` is optional.
40
+ *
41
+ * @default undefined
42
+ */
43
+ tokensDirectory?: string;
36
44
  }
37
45
 
38
46
  /**
@@ -63,6 +71,14 @@ interface InterceptorServer {
63
71
  * @see {@link https://github.com/zimicjs/zimic/wiki/cli‐zimic‐server#zimic-server `zimic-interceptor server` API reference}
64
72
  */
65
73
  logUnhandledRequests: boolean;
74
+ /**
75
+ * The directory where the authorized interceptor authentication tokens are saved. If provided, only remote
76
+ * interceptors bearing a valid token will be accepted. This option is essential if you are exposing your interceptor
77
+ * server publicly. For local development and testing, though, `--tokens-dir` is optional.
78
+ *
79
+ * @default undefined
80
+ */
81
+ tokensDirectory?: string;
66
82
  /**
67
83
  * Whether the server is running.
68
84
  *
package/dist/server.js CHANGED
@@ -1,29 +1,29 @@
1
1
  'use strict';
2
2
 
3
- var chunkTYHJPU5G_js = require('./chunk-TYHJPU5G.js');
3
+ var chunkMXHLBRPB_js = require('./chunk-MXHLBRPB.js');
4
4
  require('./chunk-WCQVDF3K.js');
5
5
 
6
6
 
7
7
 
8
8
  Object.defineProperty(exports, "DEFAULT_ACCESS_CONTROL_HEADERS", {
9
9
  enumerable: true,
10
- get: function () { return chunkTYHJPU5G_js.DEFAULT_ACCESS_CONTROL_HEADERS; }
10
+ get: function () { return chunkMXHLBRPB_js.DEFAULT_ACCESS_CONTROL_HEADERS; }
11
11
  });
12
12
  Object.defineProperty(exports, "DEFAULT_PREFLIGHT_STATUS_CODE", {
13
13
  enumerable: true,
14
- get: function () { return chunkTYHJPU5G_js.DEFAULT_PREFLIGHT_STATUS_CODE; }
14
+ get: function () { return chunkMXHLBRPB_js.DEFAULT_PREFLIGHT_STATUS_CODE; }
15
15
  });
16
16
  Object.defineProperty(exports, "NotRunningInterceptorServerError", {
17
17
  enumerable: true,
18
- get: function () { return chunkTYHJPU5G_js.NotRunningInterceptorServerError_default; }
18
+ get: function () { return chunkMXHLBRPB_js.NotRunningInterceptorServerError_default; }
19
19
  });
20
20
  Object.defineProperty(exports, "RunningInterceptorServerError", {
21
21
  enumerable: true,
22
- get: function () { return chunkTYHJPU5G_js.RunningInterceptorServerError_default; }
22
+ get: function () { return chunkMXHLBRPB_js.RunningInterceptorServerError_default; }
23
23
  });
24
24
  Object.defineProperty(exports, "createInterceptorServer", {
25
25
  enumerable: true,
26
- get: function () { return chunkTYHJPU5G_js.createInterceptorServer; }
26
+ get: function () { return chunkMXHLBRPB_js.createInterceptorServer; }
27
27
  });
28
28
  //# sourceMappingURL=server.js.map
29
29
  //# sourceMappingURL=server.js.map
package/dist/server.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { DEFAULT_ACCESS_CONTROL_HEADERS, DEFAULT_PREFLIGHT_STATUS_CODE, NotRunningInterceptorServerError_default as NotRunningInterceptorServerError, RunningInterceptorServerError_default as RunningInterceptorServerError, createInterceptorServer } from './chunk-3SKHNQLL.mjs';
1
+ export { DEFAULT_ACCESS_CONTROL_HEADERS, DEFAULT_PREFLIGHT_STATUS_CODE, NotRunningInterceptorServerError_default as NotRunningInterceptorServerError, RunningInterceptorServerError_default as RunningInterceptorServerError, createInterceptorServer } from './chunk-OGL76CKO.mjs';
2
2
  import './chunk-CGILA3WO.mjs';
3
3
  //# sourceMappingURL=server.mjs.map
4
4
  //# sourceMappingURL=server.mjs.map
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "api",
15
15
  "static"
16
16
  ],
17
- "version": "0.17.0-canary.2",
17
+ "version": "0.17.0-canary.4",
18
18
  "repository": {
19
19
  "type": "git",
20
20
  "url": "https://github.com/zimicjs/zimic.git",
@@ -81,27 +81,28 @@
81
81
  "msw": "2.7.3",
82
82
  "picocolors": "^1.1.1",
83
83
  "ws": "8.18.1",
84
- "yargs": "17.7.2"
84
+ "yargs": "17.7.2",
85
+ "zod": "^3.24.2"
85
86
  },
86
87
  "optionalDependencies": {
87
88
  "bufferutil": "4.0.9"
88
89
  },
89
90
  "devDependencies": {
90
- "@types/node": "^22.13.14",
91
- "@types/ws": "^8.18.0",
91
+ "@types/node": "^22.14.0",
92
+ "@types/ws": "^8.18.1",
92
93
  "@types/yargs": "^17.0.33",
93
- "@vitest/browser": "^3.0.9",
94
- "@vitest/coverage-istanbul": "^3.0.9",
94
+ "@vitest/browser": "^3.1.1",
95
+ "@vitest/coverage-istanbul": "^3.1.1",
95
96
  "dotenv-cli": "^8.0.0",
96
- "eslint": "^9.23.0",
97
+ "eslint": "^9.24.0",
97
98
  "playwright": "^1.51.1",
98
99
  "tsup": "^8.4.0",
99
- "typescript": "^5.8.2",
100
- "vitest": "^3.0.9",
100
+ "typescript": "^5.8.3",
101
+ "vitest": "^3.1.1",
101
102
  "@zimic/eslint-config-node": "0.0.0",
102
- "@zimic/tsconfig": "0.0.0",
103
103
  "@zimic/lint-staged-config": "0.0.0",
104
- "@zimic/utils": "0.0.0"
104
+ "@zimic/utils": "0.0.0",
105
+ "@zimic/tsconfig": "0.0.0"
105
106
  },
106
107
  "peerDependencies": {
107
108
  "@zimic/http": "^0.3.0 || ^0.3.0-canary.0",
@@ -1,8 +1,8 @@
1
- import filesystem from 'fs/promises';
1
+ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import color from 'picocolors';
4
4
 
5
- import { logWithPrefix } from '@/utils/console';
5
+ import { logger } from '@/utils/logging';
6
6
 
7
7
  import { SERVICE_WORKER_FILE_NAME } from './shared/constants';
8
8
 
@@ -15,13 +15,12 @@ interface BrowserServiceWorkerInitOptions {
15
15
 
16
16
  async function initializeBrowserServiceWorker({ publicDirectory }: BrowserServiceWorkerInitOptions) {
17
17
  const absolutePublicDirectory = path.resolve(publicDirectory);
18
- await filesystem.mkdir(absolutePublicDirectory, { recursive: true });
18
+ await fs.promises.mkdir(absolutePublicDirectory, { recursive: true });
19
19
 
20
20
  const destinationPath = path.join(absolutePublicDirectory, SERVICE_WORKER_FILE_NAME);
21
- await filesystem.copyFile(MOCK_SERVICE_WORKER_PATH, destinationPath);
21
+ await fs.promises.copyFile(MOCK_SERVICE_WORKER_PATH, destinationPath);
22
22
 
23
- logWithPrefix(`Service worker script saved to ${color.green(destinationPath)}!`);
24
- logWithPrefix('You can now use browser interceptors!');
23
+ logger.info(`Service worker script saved to ${color.magenta(destinationPath)}.`);
25
24
  }
26
25
 
27
26
  export default initializeBrowserServiceWorker;
package/src/cli/cli.ts CHANGED
@@ -3,8 +3,12 @@ import { hideBin } from 'yargs/helpers';
3
3
 
4
4
  import { version } from '@@/package.json';
5
5
 
6
+ import { DEFAULT_INTERCEPTOR_TOKENS_DIRECTORY } from '../server/utils/auth';
6
7
  import initializeBrowserServiceWorker from './browser/init';
7
8
  import startInterceptorServer from './server/start';
9
+ import { createInterceptorServerToken } from './server/token/create';
10
+ import { listInterceptorServerTokens } from './server/token/list';
11
+ import { removeInterceptorServerToken } from './server/token/remove';
8
12
 
9
13
  async function runCLI() {
10
14
  await yargs(hideBin(process.argv))
@@ -13,7 +17,7 @@ async function runCLI() {
13
17
  .showHelpOnFail(false)
14
18
  .strict()
15
19
 
16
- .command('browser', 'Manage your browser mock configuration', (yargs) =>
20
+ .command('browser', 'Manage your browser mock configuration.', (yargs) =>
17
21
  yargs.demandCommand().command(
18
22
  'init <publicDirectory>',
19
23
  'Initialize the browser service worker configuration.',
@@ -31,62 +35,143 @@ async function runCLI() {
31
35
  ),
32
36
  )
33
37
 
34
- .command('server', 'Manage interceptor servers', (yargs) =>
35
- yargs.demandCommand().command(
36
- 'start [-- onReady]',
37
- 'Start an interceptor server.',
38
- (yargs) =>
38
+ .command('server', 'Manage interceptor servers.', (yargs) =>
39
+ yargs
40
+ .demandCommand()
41
+ .command(
42
+ 'start [-- onReady]',
43
+ 'Start an interceptor server.',
44
+ (yargs) =>
45
+ yargs
46
+ .positional('onReady', {
47
+ description: 'A command to run when the server is ready to accept connections.',
48
+ type: 'string',
49
+ })
50
+ .option('hostname', {
51
+ type: 'string',
52
+ description: 'The hostname to start the server on.',
53
+ alias: 'h',
54
+ default: 'localhost',
55
+ })
56
+ .option('port', {
57
+ type: 'number',
58
+ description: 'The port to start the server on.',
59
+ alias: 'p',
60
+ })
61
+ .option('ephemeral', {
62
+ type: 'boolean',
63
+ description:
64
+ 'Whether the server should stop automatically after the on-ready command finishes. ' +
65
+ 'If no on-ready command is provided and ephemeral is true, the server will stop immediately after ' +
66
+ 'starting.',
67
+ alias: 'e',
68
+ default: false,
69
+ })
70
+ .option('log-unhandled-requests', {
71
+ type: 'boolean',
72
+ description:
73
+ 'Whether to log a warning when no interceptors were found for the base URL of a request. ' +
74
+ 'If an interceptor was matched, the logging behavior for that base URL is configured in the ' +
75
+ 'interceptor itself.',
76
+ alias: 'l',
77
+ })
78
+ .option('tokens-dir', {
79
+ type: 'string',
80
+ description:
81
+ 'The directory where the authorized interceptor authentication tokens are saved. If provided, only ' +
82
+ 'remote interceptors bearing a valid token will be accepted. This option is essential if you are ' +
83
+ 'exposing your interceptor server publicly. For local development and testing, though, ' +
84
+ '`--tokens-dir` is optional.',
85
+ alias: 't',
86
+ }),
87
+ async (cliArguments) => {
88
+ const onReadyCommand = cliArguments._.at(2)?.toString();
89
+ const onReadyCommandArguments = cliArguments._.slice(3).map((argument) => argument.toString());
90
+
91
+ await startInterceptorServer({
92
+ hostname: cliArguments.hostname,
93
+ port: cliArguments.port,
94
+ ephemeral: cliArguments.ephemeral,
95
+ logUnhandledRequests: cliArguments.logUnhandledRequests,
96
+ tokensDirectory: cliArguments.tokensDir,
97
+ onReady: onReadyCommand
98
+ ? {
99
+ command: onReadyCommand.toString(),
100
+ arguments: onReadyCommandArguments,
101
+ }
102
+ : undefined,
103
+ });
104
+ },
105
+ )
106
+
107
+ .command('token', 'Manage remote interceptor authentication tokens.', (yargs) =>
39
108
  yargs
40
- .positional('onReady', {
41
- description: 'A command to run when the server is ready to accept connections.',
42
- type: 'string',
43
- })
44
- .option('hostname', {
45
- type: 'string',
46
- description: 'The hostname to start the server on.',
47
- alias: 'h',
48
- default: 'localhost',
49
- })
50
- .option('port', {
51
- type: 'number',
52
- description: 'The port to start the server on.',
53
- alias: 'p',
54
- })
55
- .option('ephemeral', {
56
- type: 'boolean',
57
- description:
58
- 'Whether the server should stop automatically after the on-ready command finishes. ' +
59
- 'If no on-ready command is provided and ephemeral is true, the server will stop immediately after ' +
60
- 'starting.',
61
- alias: 'e',
62
- default: false,
63
- })
64
- .option('log-unhandled-requests', {
65
- type: 'boolean',
66
- description:
67
- 'Whether to log a warning when no interceptors were found for the base URL of a request. ' +
68
- 'If an interceptor was matched, the logging behavior for that base URL is configured in the ' +
69
- 'interceptor itself.',
70
- alias: 'l',
71
- }),
72
- async (cliArguments) => {
73
- const onReadyCommand = cliArguments._.at(2)?.toString();
74
- const onReadyCommandArguments = cliArguments._.slice(3).map((argument) => argument.toString());
109
+ .demandCommand()
110
+ .command(
111
+ 'create',
112
+ 'Create an interceptor token.',
113
+ (yargs) =>
114
+ yargs
115
+ .option('name', {
116
+ type: 'string',
117
+ description: 'The name of the token to create.',
118
+ alias: 'n',
119
+ })
120
+ .option('tokens-dir', {
121
+ type: 'string',
122
+ description: 'The directory where the created interceptor token will be saved.',
123
+ alias: 't',
124
+ default: DEFAULT_INTERCEPTOR_TOKENS_DIRECTORY,
125
+ }),
126
+ async (cliArguments) => {
127
+ await createInterceptorServerToken({
128
+ tokenName: cliArguments.name,
129
+ tokensDirectory: cliArguments.tokensDir,
130
+ });
131
+ },
132
+ )
75
133
 
76
- await startInterceptorServer({
77
- hostname: cliArguments.hostname,
78
- port: cliArguments.port,
79
- ephemeral: cliArguments.ephemeral,
80
- logUnhandledRequests: cliArguments.logUnhandledRequests,
81
- onReady: onReadyCommand
82
- ? {
83
- command: onReadyCommand.toString(),
84
- arguments: onReadyCommandArguments,
85
- }
86
- : undefined,
87
- });
88
- },
89
- ),
134
+ .command(
135
+ ['ls', 'list'],
136
+ 'List the authorized interceptor tokens.',
137
+ (yargs) =>
138
+ yargs.option('tokens-dir', {
139
+ type: 'string',
140
+ description: 'The directory where the interceptor tokens are saved.',
141
+ alias: 't',
142
+ default: DEFAULT_INTERCEPTOR_TOKENS_DIRECTORY,
143
+ }),
144
+ async (cliArguments) => {
145
+ await listInterceptorServerTokens({
146
+ tokensDirectory: cliArguments.tokensDir,
147
+ });
148
+ },
149
+ )
150
+
151
+ .command(
152
+ ['rm <tokenId>', 'remove <tokenId>'],
153
+ 'Remove an interceptor token.',
154
+ (yargs) =>
155
+ yargs
156
+ .positional('tokenId', {
157
+ type: 'string',
158
+ description: 'The identifier of the token to remove.',
159
+ demandOption: true,
160
+ })
161
+ .option('tokens-dir', {
162
+ type: 'string',
163
+ description: 'The directory where the interceptor tokens are saved.',
164
+ alias: 't',
165
+ default: DEFAULT_INTERCEPTOR_TOKENS_DIRECTORY,
166
+ }),
167
+ async (cliArguments) => {
168
+ await removeInterceptorServerToken({
169
+ tokenId: cliArguments.tokenId,
170
+ tokensDirectory: cliArguments.tokensDir,
171
+ });
172
+ },
173
+ ),
174
+ ),
90
175
  )
91
176
 
92
177
  .parse();
@@ -1,6 +1,8 @@
1
+ import color from 'picocolors';
2
+
1
3
  import { InterceptorServer, createInterceptorServer } from '@/server';
2
4
  import { InterceptorServerOptions } from '@/server/types/options';
3
- import { logWithPrefix } from '@/utils/console';
5
+ import { logger } from '@/utils/logging';
4
6
  import {
5
7
  CommandError,
6
8
  PROCESS_EXIT_CODE_BY_EXIT_EVENT,
@@ -11,10 +13,7 @@ import {
11
13
 
12
14
  interface InterceptorServerStartOptions extends InterceptorServerOptions {
13
15
  ephemeral: boolean;
14
- onReady?: {
15
- command: string;
16
- arguments: string[];
17
- };
16
+ onReady?: { command: string; arguments: string[] };
18
17
  }
19
18
 
20
19
  export let serverSingleton: InterceptorServer | undefined;
@@ -22,14 +21,16 @@ export let serverSingleton: InterceptorServer | undefined;
22
21
  async function startInterceptorServer({
23
22
  hostname,
24
23
  port,
25
- ephemeral,
26
24
  logUnhandledRequests,
25
+ tokensDirectory,
26
+ ephemeral,
27
27
  onReady,
28
28
  }: InterceptorServerStartOptions) {
29
29
  const server = createInterceptorServer({
30
30
  hostname,
31
31
  port,
32
32
  logUnhandledRequests,
33
+ tokensDirectory,
33
34
  });
34
35
 
35
36
  async function handleExitEvent(exitEvent: ProcessExitEvent | undefined) {
@@ -59,7 +60,21 @@ async function startInterceptorServer({
59
60
 
60
61
  await server.start();
61
62
 
62
- logWithPrefix(`${ephemeral ? 'Ephemeral s' : 'S'}erver is running on ${server.hostname}:${server.port}`);
63
+ logger.info(
64
+ `${ephemeral ? 'Ephemeral s' : 'S'}erver is running on ${color.yellow(`${server.hostname}:${server.port}`)}`,
65
+ );
66
+
67
+ const isDangerouslyUnprotected = !tokensDirectory && process.env.NODE_ENV === 'production';
68
+
69
+ if (isDangerouslyUnprotected) {
70
+ logger.warn(
71
+ [
72
+ `Attention: this interceptor server is ${color.bold(color.red('unprotected'))}. Do not expose it publicly without authentication.`,
73
+ '',
74
+ 'Learn more: https://github.com/zimicjs/zimic/wiki/cli‐zimic‐interceptor‐server#authentication',
75
+ ].join('\n'),
76
+ );
77
+ }
63
78
 
64
79
  if (onReady) {
65
80
  try {
@@ -0,0 +1,33 @@
1
+ import color from 'picocolors';
2
+
3
+ import { createInterceptorToken } from '@/server/utils/auth';
4
+ import { logger } from '@/utils/logging';
5
+
6
+ interface InterceptorServerCreateTokenOptions {
7
+ tokenName?: string;
8
+ tokensDirectory: string;
9
+ }
10
+
11
+ export async function createInterceptorServerToken({
12
+ tokenName,
13
+ tokensDirectory,
14
+ }: InterceptorServerCreateTokenOptions) {
15
+ const token = await createInterceptorToken({ name: tokenName, tokensDirectory });
16
+
17
+ logger.info(
18
+ [
19
+ `${color.green(color.bold('✔'))} Token${tokenName ? ` ${color.green(tokenName)}` : ''} created:`,
20
+ '',
21
+ color.yellow(token.value),
22
+ '',
23
+ 'Store this token securely. It cannot be retrieved later.',
24
+ '',
25
+ `To enable authentication in your interceptor server, use the ${color.cyan('--tokens-dir')} option as shown ` +
26
+ 'below. Only remote interceptors bearing a valid token will be allowed to connect.',
27
+ '',
28
+ `${color.dim('$')} zimic-interceptor server start ${color.cyan('--tokens-dir')} ${color.magenta(tokensDirectory)}`,
29
+ '',
30
+ 'Learn more: https://github.com/zimicjs/zimic/wiki/cli‐zimic‐interceptor‐server#authentication',
31
+ ].join('\n'),
32
+ );
33
+ }
@@ -0,0 +1,23 @@
1
+ import { listInterceptorTokens } from '@/server/utils/auth';
2
+ import { logger } from '@/utils/logging';
3
+
4
+ interface InterceptorServerListTokensOptions {
5
+ tokensDirectory: string;
6
+ }
7
+
8
+ export async function listInterceptorServerTokens({ tokensDirectory }: InterceptorServerListTokensOptions) {
9
+ const tokens = await listInterceptorTokens({ tokensDirectory });
10
+
11
+ logger.raw.table(
12
+ [
13
+ { title: 'ID', property: 'id' },
14
+ { title: 'NAME', property: 'name' },
15
+ { title: 'CREATED AT', property: 'createdAt' },
16
+ ],
17
+ tokens.map((token) => ({
18
+ id: token.id,
19
+ name: token.name ?? '',
20
+ createdAt: token.createdAt.toISOString(),
21
+ })),
22
+ );
23
+ }
@@ -0,0 +1,22 @@
1
+ import color from 'picocolors';
2
+
3
+ import { readInterceptorTokenFromFile, removeInterceptorToken } from '@/server/utils/auth';
4
+ import { logger } from '@/utils/logging';
5
+
6
+ interface InterceptorServerCreateTokenOptions {
7
+ tokenId: string;
8
+ tokensDirectory: string;
9
+ }
10
+
11
+ export async function removeInterceptorServerToken({ tokenId, tokensDirectory }: InterceptorServerCreateTokenOptions) {
12
+ const token = await readInterceptorTokenFromFile(tokenId, { tokensDirectory });
13
+
14
+ if (!token) {
15
+ logger.error(`${color.red(color.bold('✘'))} Token ${color.red(tokenId)} not found.`);
16
+ process.exit(1);
17
+ }
18
+
19
+ await removeInterceptorToken(token.id, { tokensDirectory });
20
+
21
+ logger.info(`${color.green(color.bold('✔'))} Token ${color.green(token.name ?? token.id)} removed.`);
22
+ }