@hubspot/cli 4.2.1-beta.1 → 4.2.1-beta.3

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.
@@ -28,8 +28,8 @@ const { promptUser } = require('../../lib/prompts/promptUtils');
28
28
  const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
29
29
  const {
30
30
  isSpecifiedError,
31
+ isSpecifiedHubSpotAuthError,
31
32
  } = require('@hubspot/cli-lib/errorHandlers/apiErrors');
32
- const { HubSpotAuthError } = require('@hubspot/cli-lib/lib/models/Errors');
33
33
  const { getAccountName } = require('../../lib/sandboxes');
34
34
  const { getValidEnv } = require('@hubspot/cli-lib/lib/environment');
35
35
 
@@ -168,19 +168,15 @@ exports.handler = async options => {
168
168
  } catch (err) {
169
169
  debugErrorAndContext(err);
170
170
 
171
- if (err instanceof HubSpotAuthError) {
171
+ if (isSpecifiedHubSpotAuthError(err, { statusCode: 401 })) {
172
172
  // Intercept invalid key error
173
173
  // This command uses the parent portal PAK to delete a sandbox, so we must specify which account needs a new key
174
- const regex = /\bYour personal access key is invalid\b/;
175
- const match = err.message.match(regex);
176
- if (match && match[0]) {
177
- logger.log('');
178
- logger.error(
179
- i18n(`${i18nKey}.failure.invalidKey`, {
180
- account: getAccountName(parentAccount),
181
- })
182
- );
183
- }
174
+ logger.log('');
175
+ logger.error(
176
+ i18n(`${i18nKey}.failure.invalidKey`, {
177
+ account: getAccountName(parentAccount),
178
+ })
179
+ );
184
180
  } else if (
185
181
  isSpecifiedError(err, {
186
182
  statusCode: 403,
@@ -1,12 +1,13 @@
1
1
  const { addConfigOptions, addAccountOptions } = require('../lib/commonOpts');
2
+ const { i18n } = require('../lib/lang');
2
3
  const create = require('./sandbox/create');
3
4
  const del = require('./sandbox/delete');
4
5
  const sync = require('./sandbox/sync');
5
6
 
6
- // const i18nKey = 'cli.commands.sandbox';
7
+ const i18nKey = 'cli.commands.sandbox';
7
8
 
8
9
  exports.command = 'sandbox';
9
- exports.describe = false; // i18n(`${i18nKey}.describe`);
10
+ exports.describe = i18n(`${i18nKey}.describe`);
10
11
 
11
12
  exports.builder = yargs => {
12
13
  addConfigOptions(yargs, true);
package/lang/en.lyaml CHANGED
@@ -67,6 +67,18 @@ en:
67
67
  nameBased: "Print information for the account in the config with name equal to \"MyAccount\""
68
68
  name: "{{#bold}}Account name{{/bold}}: {{ name }}"
69
69
  scopeGroups: "{{#bold}}Scopes available{{/bold}}:"
70
+ clean:
71
+ describe: "Checks for inactive accounts and removes them from the CLI config"
72
+ noResults: "No inactive accounts found to remove."
73
+ loading:
74
+ add: "Looking for inactive accounts…"
75
+ inactiveAccountsFound:
76
+ one: "1 inactive account found:"
77
+ other: "{{ count }} inactive accounts found:"
78
+ confirm:
79
+ one: "Remove 1 inactive account from the CLI config?"
80
+ other: "Remove {{ count }} inactive accounts from the CLI config?"
81
+ removeSuccess: "Removed {{ accountName }} from the CLI config."
70
82
  auth:
71
83
  describe: "Configure authentication for a HubSpot account. Supported authentication protocols are {{ supportedProtocols }}."
72
84
  errors:
@@ -444,9 +456,10 @@ en:
444
456
  describe: "Shortcut of the link you'd like to open"
445
457
  selectLink: "Select a link to open"
446
458
  project:
459
+ describe: "{{#bold}}[beta]{{/bold}} Commands for working with projects. For more information, visit our documentation: https://developers.hubspot.com/docs/platform/build-and-deploy-using-hubspot-projects"
447
460
  subcommands:
448
461
  dev:
449
- describe: "Start local dev for the current project"
462
+ describe: "{{#bold}}[beta]{{/bold}} Start local dev for the current project"
450
463
  logs:
451
464
  betaMessage: "HubSpot projects local development"
452
465
  nonSandboxWarning: "Testing in a sandbox is strongly recommended. To switch the target account, select an option below or run {{#bold}}`hs accounts use`{{/bold}} before running the command again."
@@ -454,24 +467,20 @@ en:
454
467
  projectMustExistExplanation: "The project {{ projectName }} does not exist in the target account {{ accountIdentifier}}. This command requires the project to exist in the target account."
455
468
  choseNotToCreateProject: "Exiting because this command requires the project to exist in the target account."
456
469
  initialUploadMessage: "HubSpot Local Dev Server Startup"
470
+ declineDefaultSandboxExplanation: "To develop on a different account, run {{ useCommand }} to change your default account, then re-run {{ devCommand }}."
457
471
  status:
458
472
  creatingProject: "Creating project {{ projectName }} in {{ accountIdentifier }}"
459
473
  createdProject: "Created project {{ projectName }} in {{ accountIdentifier }}"
460
474
  failedToCreateProject: "Failed to create project in the target account."
461
- startupMessage: "Starting local dev server for {{#bold}}{{ projectName }}{{/bold}} ..."
462
475
  prompt:
463
476
  createProject: "Create new project {{ projectName}} in {{#bold}}[{{ accountIdentifier }}]{{/bold}}?"
464
- targetNonSandbox: "Continue testing in a non-sandbox account?"
465
- options:
466
- extension:
467
- describe: "The extension that you would like to run locally"
468
477
  errors:
469
478
  noProjectConfig: "No project detected. Please run this command again from a project directory."
470
- projectLockedError: "Your project is locked. This may mean that another user is running the {{#bold}}`hs project dev`{{/bold}} command for this project. If this is you, unlock the project in Projects UI."
479
+ projectLockedError: "Your project is locked. This may mean that another user is running the {{#bold}}`hs project watch`{{/bold}} command for this project. If this is you, unlock the project in Projects UI."
471
480
  examples:
472
481
  default: "Start local dev for the current project"
473
482
  create:
474
- describe: "Create a new project"
483
+ describe: "{{#bold}}[beta]{{/bold}} Create a new project"
475
484
  logs:
476
485
  welcomeMessage: "Welcome to HubSpot Developer Projects!"
477
486
  examples:
@@ -486,7 +495,7 @@ en:
486
495
  templateSource:
487
496
  describe: "Path to custom GitHub repository from which to create project template"
488
497
  add:
489
- describe: "Create a new component within a project"
498
+ describe: "{{#bold}}[beta]{{/bold}} Create a new component within a project"
490
499
  options:
491
500
  name:
492
501
  describe: "Component name"
@@ -501,7 +510,7 @@ en:
501
510
  examples:
502
511
  default: "Create a component within your project"
503
512
  deploy:
504
- describe: "Deploy a project build"
513
+ describe: "{{#bold}}[beta]{{/bold}} Deploy a project build"
505
514
  debug:
506
515
  deploying: "Deploying project at path: {{ path }}"
507
516
  errors:
@@ -516,8 +525,10 @@ en:
516
525
  describe: "Project build ID to be deployed"
517
526
  project:
518
527
  describe: "Project name"
528
+ listBuilds:
529
+ describe: "{{#bold}}[beta]{{/bold}} List the project's builds"
519
530
  logs:
520
- describe: "Get execution logs for a serverless function within a project"
531
+ describe: "{{#bold}}[beta]{{/bold}} Get execution logs for a serverless function within a project"
521
532
  errors:
522
533
  invalidAppName: "Could not find app with name \"{{ appName }}\" in project \"{{ projectName }}\""
523
534
  logs:
@@ -552,7 +563,7 @@ en:
552
563
  endpoint:
553
564
  describe: "Public endpoint path"
554
565
  upload:
555
- describe: "Upload your project files and create a new build"
566
+ describe: "{{#bold}}[beta]{{/bold}} Upload your project files and create a new build"
556
567
  examples:
557
568
  default: "Upload a project"
558
569
  logs:
@@ -570,7 +581,7 @@ en:
570
581
  path:
571
582
  describe: "Path to a project folder"
572
583
  watch:
573
- describe: "Watch your local project for changes and automatically upload changed files to a new build in HubSpot"
584
+ describe: "{{#bold}}[beta]{{/bold}} Watch your local project for changes and automatically upload changed files to a new build in HubSpot"
574
585
  examples:
575
586
  default: "Watch a project within the myProjectFolder folder"
576
587
  logs:
@@ -582,7 +593,7 @@ en:
582
593
  initialUpload:
583
594
  describe: "Upload directory before watching for updates"
584
595
  download:
585
- describe: "Download your project files from HubSpot and write to a path on your computer"
596
+ describe: "{{#bold}}[beta]{{/bold}} Download your project files from HubSpot and write to a path on your computer"
586
597
  examples:
587
598
  default: "Download the project myProject into myProjectFolder folder"
588
599
  logs:
@@ -591,6 +602,8 @@ en:
591
602
  errors:
592
603
  downloadFailed: "Something went wrong downloading the project"
593
604
  projectNotFound: "Your project {{ projectName }} could not be found in {{ accountId }}"
605
+ warnings:
606
+ cannotDownloadWithinProject: "Cancelling project download. Please run the command again outside the context of an existing project."
594
607
  options:
595
608
  buildNumber:
596
609
  describe: "The build number to download"
@@ -599,7 +612,7 @@ en:
599
612
  dest:
600
613
  describe: "Destination folder for the project"
601
614
  open:
602
- describe: "Open available projects for the specified account"
615
+ describe: "{{#bold}}[beta]{{/bold}} Open the specified project's details page in the browser"
603
616
  options:
604
617
  project:
605
618
  describe: "Name of project to open"
@@ -848,58 +861,35 @@ en:
848
861
  lib:
849
862
  DevServerManager:
850
863
  portConflict: "The port {{ port }} is already in use."
851
- LocalDevManagerV2:
864
+ notInitialized: "The Dev Server Manager must be initialized before it is started."
865
+ noCompatibleComponents: "Skipping call to {{ serverKey }} because there are no compatible components in the project."
866
+ LocalDevManager:
852
867
  failedToInitialize: "Missing required arguments to initialize Local Dev"
868
+ noComponents: "There are no components in this project."
869
+ noDeployedBuild: "There is no deployed build for this project in {{ accountIdentifier }}."
870
+ noRunnableComponents: "There are no components in this project that support local development."
853
871
  betaMessage: "HubSpot projects local development"
854
872
  running: "Running {{#bold}}{{ projectName }}{{/bold}} locally on {{ accountIdentifier }}, waiting for changes ..."
855
873
  quitHelper: "Press {{#bold}}'q'{{/bold}} to stop the local dev server"
856
- viewInHubSpotLink: "View in HubSpot"
874
+ viewInHubSpotLink: "View project in HubSpot"
857
875
  exitingStart: "Stopping local dev server ..."
858
876
  exitingSucceed: "Successfully exited"
859
877
  exitingFail: "Failed to cleanup before exiting"
878
+ uploadWarning:
879
+ appLabel: "[App]"
880
+ uiExtensionLabel: "[UI Extension]"
881
+ configEdit: "You edited the configuration file {{#bold}}{{ path }}{{/bold}}. Changes to configuration files cannot be handled by the local dev server."
882
+ missingComponents: "The deployed build for this project does not contain {{#bold}}'{{ missingComponents }}'{{/bold}}. This may cause issues in local development."
883
+ header: "{{ reason }} To reflect these changes:"
884
+ stopDev: " * Stop {{ command }}"
885
+ runUpload: " * Run {{ command }}"
886
+ runUploadWithAccount: " * Run {{ command }}"
887
+ restartDev: " * Re-run {{ command }}"
860
888
  devServer:
861
889
  cleanupError: "Failed to cleanup local dev server: {{ message }}"
890
+ setupError: "Failed to setup local dev server: {{ message }}"
862
891
  startError: "Failed to start local dev server: {{ message }}"
863
- LocalDevManager:
864
- failedToInitialize: "Missing required arguments to initialize Local Dev Manager"
865
- exitingStart: "Stopping local dev server ..."
866
- exitingSucceed: "Successfully exited"
867
- exitingFail: "Failed to clean up before exiting"
868
- previousStagingBuildCancelled: "Failed to create a staging build because the project was already locked. It is now unlocked. Run the command again."
869
- cancelledFromUI: "The dev process has been cancelled from the UI. Any changes made since cancelling have not been uploaded. To resume dev mode, rerun {{#yellow}}`hs project dev`{{/yellow}}."
870
- header:
871
- betaMessage: "{{#yellow}}{{#bold}}[beta]{{/bold}}{{/yellow}} HubSpot projects local development"
872
- running: "Running {{#bold}}{{ projectName }}{{/bold}} locally on {{ accountIdentifier }}, waiting for changes ..."
873
- quitHelper: "Press {{#bold}}'q'{{/bold}} to stop the local dev server"
874
- viewInHubSpotLink: "View in HubSpot"
875
- status:
876
- clean: "{{#bold}}Status:{{/bold}} {{#green}}Everything up to date{{/green}}"
877
- buildError: "{{#bold}}Status:{{/bold}} {{#red}}Latest build failed{{/red}}"
878
- deployError: "{{#bold}}Status:{{/bold}} {{#red}}Latest deploy failed{{/red}}"
879
- uploadPending: "{{#bold}}Status:{{/bold}} {{#yellow}}Upload is pending{{/yellow}}"
880
- noUploadsAllowed: "{{#bold}}Status:{{/bold}} {{#red}}Change requires upload, but uploads are not allowed{{/red}}"
881
- manualUploadRequired: "{{#bold}}Status:{{/bold}} {{#yellow}}Change requires manual upload{{/yellow}}"
882
- manualUpload: "{{#bold}}Status:{{/bold}} {{#green}}Manually uploading pending changes{{/green}}"
883
- upload:
884
- noUploadsAllowed: "The change to {{ filePath }} requires an upload, but the CLI cannot upload to a project that is using a github integration."
885
- manualUploadSkipped: "Manually upload and deploy project to production account: {{#green}}(n){{/green}}"
886
- manualUploadConfirmed: "Manually upload and deploy project to production account: {{#green}}(Y){{/green}}"
887
- manualUploadRequired: "Project file changes require a manual upload and deploy ..."
888
- manualUploadExplanation1: "{{#yellow}}> Dev server is running on a {{#bold}}non-sandbox account{{/bold}}.{{/yellow}}"
889
- manualUploadExplanation2: "{{#yellow}}> Uploading changes may overwrite production data.{{/yellow}}"
890
- manualUploadPrompt: "? Manually upload and deploy project? {{#green}}Y/n{{/green}}"
891
- extensionNotAllowed: "Extension not allowed for {{ filePath }}"
892
- fileIgnored: "File ignored: {{ filePath }}"
893
- uploadingAddChange: "[INFO] Uploading {{ filePath }}"
894
- uploadedAddChange: "[INFO] Uploaded {{ filePath }}"
895
- uploadingRemoveChange: "[INFO] Removing {{ filePath }}"
896
- uploadedRemoveChange: "[INFO] Removed {{ filePath }}"
897
- uploadingChanges: "{{#bold}}Building #{{ buildId }} and deploying recent changes on {{ accountIdentifier }}{{/bold}}"
898
- uploadedChangesSucceeded: "{{#bold}}Built #{{ buildId }} and deployed recent changes on {{ accountIdentifier }}{{/bold}}"
899
- uploadedChangesFailed: "{{#bold}}Failed to build #{{ buildId }} and deploy recent changes on {{ accountIdentifier }}{{/bold}}"
900
- devServer:
901
- startError: "{{#red}}[ERROR]{{/red}} Failed to start local dev server"
902
- cleanupError: "{{#red}}[ERROR]{{/red}} Failed to cleanup local dev server"
892
+ fileChangeError: "Failed to notify local dev server of file change: {{ message }}"
903
893
  projects:
904
894
  uploadProjectFiles:
905
895
  add: "Uploading {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}"
@@ -914,6 +904,8 @@ en:
914
904
  createPrompt: "The project {{ projectName }} does not exist in {{ accountIdentifier }}. Would you like to create it?"
915
905
  createSuccess: "New project {{#bold}}{{ projectName }}{{/bold}} successfully created in {{#bold}}{{ accountIdentifier }}{{/bold}}."
916
906
  notFound: "Your project {{#bold}}{{ projectName }}{{/bold}} could not be found in {{#bold}}{{ accountIdentifier }}{{/bold}}."
907
+ pollFetchProject:
908
+ checkingProject: "Checking if project exists in {{ accountIdentifier }}"
917
909
  makePollTaskStatusFunc:
918
910
  componentCountSingular: "Found 1 component in this project"
919
911
  componentCount: "Found {{ numComponents }} components in this project"
@@ -925,8 +917,11 @@ en:
925
917
  logFeedbackMessage:
926
918
  feedbackHeader: "We'd love to hear your feedback!"
927
919
  feedbackMessage: "How are you liking the new projects and developer tools? \n > Run `{{#yellow}}hs feedback{{/yellow}}` to let us know what you think!\n"
920
+ showPlatformVersionWarning:
921
+ noPlatformVersion: "No platformVersion found in hsproject.json. Falling back to version \"{{ defaultVersion }}\"."
922
+ noPlatformVersionAlt: "No platformVersion found in hsproject.json. Falling back to default version."
928
923
  ui:
929
- betaTag: "{{#bold}}[beta]{{/bold}}"
924
+ betaTag: "{{#bold}}[BETA]{{/bold}}"
930
925
  betaWarning:
931
926
  header: "{{#yellow}}***************************** WARNING ****************************{{/yellow}}"
932
927
  footer: "{{#yellow}}******************************************************************{{/yellow}}"
@@ -992,9 +987,10 @@ en:
992
987
  prompts:
993
988
  projectDevTargetAccountPrompt:
994
989
  createNewSandboxOption: "<Test on a new development sandbox>"
995
- chooseDefaultAccountOption: "<{{#bold}}!{{/bold}} Test on this production account {{#bold}}!{{/bold}}>"
990
+ chooseDefaultAccountOption: "<{{#bold}}\U00002757{{/bold}} Test on this production account {{#bold}}\U00002757{{/bold}}>"
996
991
  promptMessage: "[--account] Choose a sandbox under {{ accountIdentifier }} to test with:"
997
992
  sandboxLimit: "You’ve reached the limit of {{ limit }} development sandboxes"
993
+ confirmDefaultSandboxAccount: "Continue testing on {{#bold}}{{ accountName }} ({{ accountType }}){{/bold}}? (Y/n)"
998
994
  projectLogsPrompt:
999
995
  projectName:
1000
996
  message: "[--project] Enter the project name:"
@@ -1,31 +1,30 @@
1
- const express = require('express');
2
- const bodyParser = require('body-parser');
3
- const cors = require('cors');
4
- const { walk } = require('@hubspot/cli-lib/lib/walk');
5
- const { getProjectDetailUrl } = require('./projects');
6
- const { i18n } = require('./lang');
7
- const { EXIT_CODES } = require('./enums/exitCodes');
1
+ const httpClient = require('@hubspot/cli-lib/http');
8
2
  const { logger } = require('@hubspot/cli-lib/logger');
3
+ const { COMPONENT_TYPES } = require('./projectStructure');
4
+ const { i18n } = require('./lang');
5
+ const { promptUser } = require('./prompts/promptUtils');
6
+ const { DevModeInterface } = require('@hubspot/ui-extensions-dev-server');
9
7
 
10
8
  const i18nKey = 'cli.lib.DevServerManager';
11
9
 
12
- const DEFAULT_PORT = 8080;
10
+ const SERVER_KEYS = {
11
+ app: 'app',
12
+ };
13
13
 
14
14
  class DevServerManager {
15
15
  constructor() {
16
16
  this.initialized = false;
17
+ this.started = false;
18
+ this.componentsByType = {};
17
19
  this.server = null;
18
20
  this.path = null;
19
- this.devServers = {};
20
- }
21
-
22
- safeLoadServer() {
23
- try {
24
- const { DevModeInterface } = require('@hubspot/ui-extensions-dev-server');
25
- this.devServers['uie'] = DevModeInterface;
26
- } catch (e) {
27
- logger.debug('Failed to load dev server interface: ', e);
28
- }
21
+ this.devServers = {
22
+ [SERVER_KEYS.app]: {
23
+ componentType: COMPONENT_TYPES.app,
24
+ serverInterface: DevModeInterface,
25
+ },
26
+ };
27
+ this.debug = false;
29
28
  }
30
29
 
31
30
  async iterateDevServers(callback) {
@@ -33,84 +32,87 @@ class DevServerManager {
33
32
 
34
33
  for (let i = 0; i < serverKeys.length; i++) {
35
34
  const serverKey = serverKeys[i];
36
- const serverInterface = this.devServers[serverKey];
37
- await callback(serverInterface, serverKey);
35
+ const devServer = this.devServers[serverKey];
36
+
37
+ const compatibleComponents =
38
+ this.componentsByType[devServer.componentType] || {};
39
+
40
+ if (Object.keys(compatibleComponents).length) {
41
+ await callback(devServer.serverInterface, compatibleComponents);
42
+ } else {
43
+ logger.debug(i18n(`${i18nKey}.noCompatibleComponents`, { serverKey }));
44
+ }
38
45
  }
39
46
  }
40
47
 
41
- generateURL(path) {
42
- return this.path ? `${this.path}/${path}` : null;
48
+ arrangeComponentsByType(components) {
49
+ return components.reduce((acc, component) => {
50
+ if (!acc[component.type]) {
51
+ acc[component.type] = {};
52
+ }
53
+
54
+ acc[component.type][component.config.name] = component;
55
+
56
+ return acc;
57
+ }, {});
43
58
  }
44
59
 
45
- async start({
46
- accountId,
47
- debug,
48
- extension,
49
- projectConfig,
50
- projectSourceDir,
51
- }) {
52
- const app = express();
53
-
54
- // Install Middleware
55
- app.use(bodyParser.json({ limit: '50mb' }));
56
- app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
57
- app.use(cors());
58
-
59
- // Configure
60
- app.set('trust proxy', true);
61
-
62
- // Initialize a base route
63
- app.get('/', (req, res) => {
64
- res.send('HubSpot local dev server');
65
- });
66
-
67
- // Initialize URL redirects
68
- app.get('/hs/project', (req, res) => {
69
- res.redirect(getProjectDetailUrl(projectConfig.name, accountId));
70
- });
71
-
72
- // Start server
73
- this.server = await app.listen(DEFAULT_PORT).on('error', err => {
74
- if (err.code === 'EADDRINUSE') {
75
- logger.error(i18n(`${i18nKey}.portConflict`, { port: DEFAULT_PORT }));
76
- logger.log();
77
- process.exit(EXIT_CODES.ERROR);
78
- }
79
- });
80
-
81
- const projectFiles = await walk(projectSourceDir);
82
-
83
- // Initialize component servers
84
- await this.iterateDevServers(async serverInterface => {
85
- if (serverInterface.start) {
86
- await serverInterface.start({
87
- accountId,
88
- debug,
89
- extension,
90
- projectConfig,
91
- projectFiles,
92
- });
60
+ async setup({ components, debug, onUploadRequired }) {
61
+ this.debug = debug;
62
+ this.componentsByType = this.arrangeComponentsByType(components);
63
+
64
+ await this.iterateDevServers(
65
+ async (serverInterface, compatibleComponents) => {
66
+ if (serverInterface.setup) {
67
+ await serverInterface.setup({
68
+ components: compatibleComponents,
69
+ debug,
70
+ onUploadRequired,
71
+ promptUser,
72
+ });
73
+ }
93
74
  }
94
- });
95
-
96
- this.path = this.server.address()
97
- ? `http://localhost:${this.server.address().port}`
98
- : null;
75
+ );
99
76
 
100
77
  this.initialized = true;
101
78
  }
102
79
 
103
- async cleanup() {
80
+ async start({ accountId, projectConfig }) {
104
81
  if (this.initialized) {
82
+ await this.iterateDevServers(async serverInterface => {
83
+ if (serverInterface.start) {
84
+ await serverInterface.start({
85
+ accountId,
86
+ debug: this.debug,
87
+ httpClient,
88
+ projectConfig,
89
+ });
90
+ }
91
+ });
92
+ } else {
93
+ throw new Error(i18n(`${i18nKey}.notInitialized`));
94
+ }
95
+
96
+ this.started = true;
97
+ }
98
+
99
+ fileChange({ filePath, event }) {
100
+ if (this.started) {
101
+ this.iterateDevServers(async serverInterface => {
102
+ if (serverInterface.fileChange) {
103
+ await serverInterface.fileChange(filePath, event);
104
+ }
105
+ });
106
+ }
107
+ }
108
+
109
+ async cleanup() {
110
+ if (this.started) {
105
111
  await this.iterateDevServers(async serverInterface => {
106
112
  if (serverInterface.cleanup) {
107
113
  await serverInterface.cleanup();
108
114
  }
109
115
  });
110
-
111
- if (this.server) {
112
- await this.server.close();
113
- }
114
116
  }
115
117
  }
116
118
  }