@hubspot/ui-extensions-dev-server 0.4.0 → 0.6.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/cli/config.js CHANGED
@@ -3,21 +3,9 @@ const path = require('path');
3
3
  const { getUrlSafeFileName } = require('../lib/utils');
4
4
  const { MAIN_APP_CONFIG } = require('../lib/constants');
5
5
 
6
- function getAppConfigPath(projectFiles) {
7
- return projectFiles.find(filePath => filePath.endsWith(MAIN_APP_CONFIG));
8
- }
9
-
10
6
  function loadConfigByPath(configPath) {
11
- if (configPath) {
12
- try {
13
- const source = fs.readFileSync(configPath);
14
- const parsedConfig = JSON.parse(source);
15
- return parsedConfig;
16
- } catch (e) {
17
- console.log(e);
18
- }
19
- }
20
- return null;
7
+ const source = fs.readFileSync(configPath);
8
+ return JSON.parse(source);
21
9
  }
22
10
 
23
11
  function loadExtensionConfig(appConfig, appPath) {
@@ -32,23 +20,28 @@ function loadExtensionConfig(appConfig, appPath) {
32
20
  const cardConfig = loadConfigByPath(cardConfigPath);
33
21
 
34
22
  if (cardConfig && cardConfig.data) {
35
- const extensionsDir = path.join(appPath, 'extensions');
23
+ const cardConfigDir = path.parse(cardConfigPath).dir;
36
24
 
37
25
  const entryPointPath = path.join(
38
- extensionsDir,
26
+ cardConfigDir,
39
27
  cardConfig.data?.module?.file
40
28
  );
41
29
 
42
30
  cardConfig.data.module.file = entryPointPath;
43
31
 
44
- outputConfig[entryPointPath] = cardConfig;
45
- outputConfig[entryPointPath].output = getUrlSafeFileName(
46
- entryPointPath
47
- );
48
- outputConfig[entryPointPath].data.appName = appConfig.name;
32
+ outputConfig[entryPointPath] = {
33
+ ...cardConfig,
34
+ output: getUrlSafeFileName(entryPointPath),
35
+ path: appPath,
36
+ extensionPath: path.parse(entryPointPath).dir,
37
+ data: {
38
+ ...cardConfig.data,
39
+ appName: appConfig.name,
40
+ },
41
+ };
49
42
  }
50
43
  } catch (e) {
51
- console.log(e);
44
+ throw new Error(`Unable to load ${cardConfigPath}`);
52
45
  }
53
46
  });
54
47
 
@@ -78,7 +71,7 @@ function loadConfig() {
78
71
  crmCardsSubConfigFiles.forEach(card => {
79
72
  const cardConfigPath = path.join(process.cwd(), '..', card.file);
80
73
  try {
81
- const cardConfig = require(cardConfigPath);
74
+ const cardConfig = loadConfigByPath(cardConfigPath);
82
75
  if (!cardConfig.data) {
83
76
  throw new Error(
84
77
  `Invalid config file at path ${cardConfigPath}, data is a required config property`
@@ -112,7 +105,6 @@ function loadConfig() {
112
105
  }
113
106
 
114
107
  module.exports = {
115
- getAppConfigPath,
116
108
  loadConfigByPath,
117
109
  loadExtensionConfig,
118
110
  loadConfig,
package/cli/logger.js CHANGED
@@ -1,19 +1,19 @@
1
1
  const { cyan, red, yellow, magenta } = require('console-log-colors');
2
2
 
3
- function info(message) {
4
- console.log(cyan(message));
3
+ function info(message, ...data) {
4
+ console.log(cyan(message), ...data);
5
5
  }
6
6
 
7
- function error(message) {
8
- console.error(red(message));
7
+ function error(message, ...data) {
8
+ console.error(red(message), ...data);
9
9
  }
10
10
 
11
- function warn(message) {
12
- console.info(yellow(message));
11
+ function warn(message, ...data) {
12
+ console.info(yellow(message), ...data);
13
13
  }
14
14
 
15
- function debug(message) {
16
- console.debug(magenta(message));
15
+ function debug(message, ...data) {
16
+ console.debug(magenta(message), ...data);
17
17
  }
18
18
 
19
19
  module.exports = { info, error, warn, debug };
package/cli/run.js CHANGED
@@ -7,26 +7,43 @@ const {
7
7
  DevModeInterface,
8
8
  } = require('../index');
9
9
 
10
- const { promptForExtensionToRun } = require('./userInput');
11
- const OUTPUT_DIR = 'dist';
12
10
  const logger = require('./logger');
13
11
  const path = require('path');
14
- const { MAIN_APP_CONFIG } = require('../lib/constants');
12
+ const { MAIN_APP_CONFIG, OUTPUT_DIR } = require('../lib/constants');
13
+ const inquirer = require('inquirer');
14
+ const { loadConfigByPath, loadExtensionConfig } = require('./config');
15
15
 
16
16
  // eslint-disable-next-line no-floating-promise/no-floating-promise
17
17
  (async () => {
18
- const { DEV_MODE, BUILD_MODE, extension, help } = parseArgs();
18
+ const { DEV_MODE, BUILD_MODE, extension, help, alpha } = parseArgs();
19
19
 
20
20
  if (help || !(DEV_MODE || BUILD_MODE)) {
21
21
  showHelp(OUTPUT_DIR);
22
22
  } else if (DEV_MODE) {
23
- DevModeInterface.start({
24
- extension: extension
25
- ? path.parse(extension).name
26
- : await promptForExtensionToRun(),
23
+ const extensionPath = process.cwd(); // Assumed to be /path/to/src/app/extensions
24
+ const appPath = path.join(extensionPath, '..');
25
+ const appConfig = loadConfigByPath(path.join(appPath, MAIN_APP_CONFIG));
26
+
27
+ let extensionConfig;
28
+ if (extension) {
29
+ const allExtensionsConfig = loadExtensionConfig(appConfig, appPath);
30
+ extensionConfig =
31
+ allExtensionsConfig[path.join(extensionPath, extension)];
32
+ }
33
+ await DevModeInterface.setup({
34
+ alpha,
35
+ promptUser: inquirer.createPromptModule(),
36
+ components: {
37
+ [appConfig.name]: {
38
+ config: appConfig,
39
+ path: path.join(extensionPath, '..'),
40
+ },
41
+ },
42
+ extensionConfig,
27
43
  logger,
28
- projectFiles: [path.join(process.cwd(), '..', MAIN_APP_CONFIG)],
29
44
  });
45
+
46
+ await DevModeInterface.start({});
30
47
  } else if (BUILD_MODE) {
31
48
  if (extension) {
32
49
  buildSingleExtension({
package/cli/utils.js CHANGED
@@ -14,6 +14,7 @@ function parseArgs() {
14
14
  const optionDefinitions = [
15
15
  { name: 'port', alias: 'p', type: Number },
16
16
  { name: 'extension', alias: 'e', type: String },
17
+ { name: 'alpha', type: Boolean },
17
18
  { name: 'help', alias: 'h', type: Boolean },
18
19
  ];
19
20
 
@@ -48,6 +49,10 @@ function showHelp(OUTPUT_DIR) {
48
49
  description:
49
50
  'The extension entrypoint file to build or start local development for',
50
51
  },
52
+ {
53
+ name: 'alpha',
54
+ description: 'Run app functions locally.',
55
+ },
51
56
  {
52
57
  name: 'help',
53
58
  alias: 'h',
@@ -1,66 +1,130 @@
1
1
  const { startDevMode } = require('./dev');
2
2
  const path = require('path');
3
3
  const { OUTPUT_DIR } = require('./constants');
4
- const {
5
- getAppConfigPath,
6
- loadConfigByPath,
7
- loadExtensionConfig,
8
- } = require('../cli/config');
4
+ const { loadExtensionConfig } = require('../cli/config');
9
5
 
10
6
  class DevModeInterface {
11
7
  constructor() {
12
- this.shutdown = null;
8
+ this._setupLogger(console);
13
9
  }
14
10
 
15
- async start({ extension, logger = console, projectFiles }) {
16
- this.logger = logger;
17
- this.logger.info('UIE Dev server initializing...');
11
+ _setupLogger(_logger) {
12
+ this.logger = {
13
+ ..._logger,
14
+ debug: (...args) => {
15
+ if (this.debug) {
16
+ _logger.debug(...args);
17
+ }
18
+ },
19
+ };
20
+ }
18
21
 
19
- const appConfigPath = getAppConfigPath(projectFiles);
20
- if (!appConfigPath) {
21
- const message = 'Unable to determine the location of the app.json file';
22
- this.logger.error(message);
23
- throw new Error(message);
24
- }
22
+ _setDataFromExtensionConfig(extensionConfig) {
23
+ this.config = extensionConfig;
24
+ this.appName = extensionConfig.data.appName;
25
+ this.title = extensionConfig.data.title;
26
+ }
25
27
 
26
- const appPath = path.dirname(appConfigPath);
27
- const appConfig = loadConfigByPath(appConfigPath);
28
- if (!appConfig) {
29
- const message = 'Unable to load app.json';
30
- this.logger.error(message);
31
- throw new Error(message);
32
- }
28
+ _generateAppExtensionMappings(components) {
29
+ // Loop over all of the app configs that are passed in
30
+ const allComponentNames = Object.keys(components);
33
31
 
34
- const extensionsConfigs = loadExtensionConfig(appConfig, appPath);
32
+ return allComponentNames.reduce((appExtensionMappings, componentName) => {
33
+ const component = components[componentName];
34
+ if (!component.config.extensions?.crm?.cards) {
35
+ return appExtensionMappings; // It's not an app
36
+ }
37
+ // Load all of the extension configs for a particular app.json file
38
+ const extensionsConfigForApp = loadExtensionConfig(
39
+ component.config,
40
+ component.path
41
+ );
35
42
 
36
- if (!extension || !extensionsConfigs) {
37
- const message =
38
- 'Unable to load the extension config, was an extension specified?';
39
- this.logger.error(message);
40
- throw new Error(message);
43
+ const extensionFilePaths = Object.keys(extensionsConfigForApp);
44
+ // Loop over the loaded extension configs and generate the list of choices to use to prompt the user for input
45
+ extensionFilePaths.forEach(extensionPath => {
46
+ const extensionConfig = extensionsConfigForApp[extensionPath];
47
+ appExtensionMappings.push({
48
+ name: `${componentName}/${extensionConfig.data.title}`,
49
+ value: extensionConfig,
50
+ });
51
+ });
52
+
53
+ return appExtensionMappings;
54
+ }, []);
55
+ }
56
+
57
+ async setup({
58
+ // This flag is used for whether to enable local serverless on the dev server pre-INBOUND.
59
+ // If the user runs `hs project dev --local-all`, the flag is set to true.
60
+ // By INBOUND, we will remove the flag and make the dev server handle both extensions
61
+ // and app functions locally.
62
+ alpha = false,
63
+ debug = false,
64
+ accountId,
65
+ httpClient,
66
+ promptUser,
67
+ components,
68
+ extensionConfig,
69
+ logger,
70
+ }) {
71
+ this.alpha = alpha;
72
+ this.debug = debug;
73
+ this.accountId = accountId;
74
+ this.httpClient = httpClient;
75
+ if (logger) {
76
+ this._setupLogger(logger);
77
+ }
78
+ if (extensionConfig) {
79
+ this._setDataFromExtensionConfig(extensionConfig);
80
+ return;
41
81
  }
42
82
 
43
- const extensionConfigKey = Object.keys(extensionsConfigs).find(
44
- extensionPath => {
45
- return (
46
- extensionPath.endsWith(`${extension}.jsx`) ||
47
- extensionPath.endsWith(`${extension}.tsx`)
48
- );
49
- }
50
- );
83
+ const choices = this._generateAppExtensionMappings(components);
84
+
85
+ if (choices.length === 0) {
86
+ throw new Error('No extensions to run');
87
+ } else if (choices.length === 1) {
88
+ this._setDataFromExtensionConfig(choices[0].value);
89
+ } else {
90
+ const answers = await promptUser({
91
+ type: 'list',
92
+ name: 'extension',
93
+ message: 'Which extension would you like to run?',
94
+ choices,
95
+ });
96
+ this._setDataFromExtensionConfig(answers.extension);
97
+ }
98
+ }
51
99
 
52
- if (!extensionConfigKey) {
53
- const message = `Unable to find config for extension: ${extension}`;
54
- this.logger.error(message);
55
- throw new Error(message);
100
+ async start({ debug }) {
101
+ this.debug = debug;
102
+ if (!this.config || !this.config.path) {
103
+ throw new Error(
104
+ 'Unable to load the required extension configuration files'
105
+ );
56
106
  }
107
+ const appPath = this.config.path;
108
+
109
+ // Pass options from the CLI for running app functions locally
110
+ const functionsConfig = {
111
+ app: { path: appPath },
112
+ accountId: this.accountId,
113
+ httpClient: this.httpClient,
114
+ enabled: !!this.alpha,
115
+ };
57
116
 
58
117
  this.shutdown = await startDevMode({
59
- extensionConfig: extensionsConfigs[extensionConfigKey],
60
- outputDir: path.join(appPath, 'extensions', OUTPUT_DIR),
118
+ extensionConfig: this.config,
119
+ outputDir: path.join(this.config.extensionPath, OUTPUT_DIR),
120
+ functionsConfig,
61
121
  logger: this.logger,
122
+ root: appPath,
62
123
  });
63
- this.logger.info('UIE Dev server done initializing...');
124
+
125
+ this.logger.info(
126
+ `Running extension '${this.title}' from app '${this.appName}'`
127
+ );
64
128
  }
65
129
 
66
130
  async cleanup() {
package/lib/build.js CHANGED
@@ -4,6 +4,7 @@ const manifestPlugin = require('./plugins/manifestPlugin');
4
4
  const path = require('path');
5
5
  const { getUrlSafeFileName } = require('./utils');
6
6
  const { loadConfig } = require('../cli/config');
7
+ const codeInjectionPlugin = require('./plugins/codeInjectionPlugin');
7
8
 
8
9
  const allowedExtensions = ['.js', '.ts', '.tsx', '.jsx'];
9
10
  const extensionErrorBaseMessage = `Supported file extensions are [${allowedExtensions.join(
@@ -20,14 +21,7 @@ async function buildAllExtensions({ outputDir, logger = console }) {
20
21
  file: data.module.file,
21
22
  outputDir,
22
23
  emptyOutDir: i === 0,
23
- plugins: {
24
- rollup: [
25
- manifestPlugin({
26
- output: getUrlSafeFileName(data.module.file),
27
- logger,
28
- }),
29
- ],
30
- },
24
+ logger,
31
25
  });
32
26
  }
33
27
  }
@@ -57,7 +51,10 @@ async function buildSingleExtension({
57
51
  },
58
52
  rollupOptions: {
59
53
  ...ROLLUP_OPTIONS,
60
- plugins: [manifestPlugin({ output, logger })],
54
+ plugins: [
55
+ manifestPlugin({ output, logger }),
56
+ codeInjectionPlugin({ file }),
57
+ ],
61
58
  },
62
59
  outDir: outputDir,
63
60
  emptyOutDir,
package/lib/constants.js CHANGED
@@ -18,9 +18,14 @@ const ROLLUP_OPTIONS = {
18
18
  },
19
19
  };
20
20
 
21
- const EXTENSIONS_MESSAGE_VERSION = 0;
21
+ const EXTENSIONS_MESSAGE_VERSION = 1;
22
22
  const WEBSOCKET_MESSAGE_VERSION = 0;
23
23
 
24
+ const SERVER_CAPABILITIES = [
25
+ // Supports running app functions locally
26
+ 'app-functions-local-dev',
27
+ ];
28
+
24
29
  module.exports = {
25
30
  ROLLUP_OPTIONS,
26
31
  OUTPUT_DIR,
@@ -30,4 +35,5 @@ module.exports = {
30
35
  VITE_DEFAULT_PORT,
31
36
  WEBSOCKET_MESSAGE_VERSION,
32
37
  WEBSOCKET_PORT,
38
+ SERVER_CAPABILITIES,
33
39
  };
package/lib/dev.js CHANGED
@@ -14,9 +14,11 @@ async function _createViteDevServer(
14
14
  extensionConfig,
15
15
  websocketPort,
16
16
  baseMessage,
17
- logger
17
+ logger,
18
+ root
18
19
  ) {
19
20
  return await createServer({
21
+ root,
20
22
  appType: 'custom',
21
23
  mode: 'development',
22
24
  server: {
@@ -48,10 +50,12 @@ async function _createViteDevServer(
48
50
 
49
51
  async function startDevMode({
50
52
  extensionConfig,
53
+ functionsConfig,
51
54
  logger,
52
55
  outputDir = OUTPUT_DIR,
53
56
  expressPort = VITE_DEFAULT_PORT,
54
57
  webSocketPort = WEBSOCKET_PORT,
58
+ root = process.cwd(),
55
59
  }) {
56
60
  if (!extensionConfig) {
57
61
  throw new Error('Unable to determine which extension to run');
@@ -68,16 +72,19 @@ async function startDevMode({
68
72
  extensionConfig,
69
73
  webSocketPort,
70
74
  baseMessage,
71
- logger
75
+ logger,
76
+ root
72
77
  );
73
- return startDevServer(
78
+
79
+ return startDevServer({
74
80
  outputDir,
75
81
  expressPort,
76
82
  webSocketPort,
77
83
  baseMessage,
78
84
  viteDevServer,
79
- logger
80
- );
85
+ functionsConfig,
86
+ logger,
87
+ });
81
88
  }
82
89
 
83
90
  module.exports = {
@@ -7,15 +7,25 @@ class ExtensionsService {
7
7
  this.endpoint = '/extensions';
8
8
  }
9
9
 
10
- add(server, webSocketPort, outputDir, baseMessage) {
10
+ add(server, webSocketPort, outputDir, baseMessage, capabilities) {
11
11
  server.get(
12
12
  this.endpoint,
13
- this.generateExtensionsHandler(baseMessage, webSocketPort, outputDir)
13
+ this.generateExtensionsHandler(
14
+ baseMessage,
15
+ webSocketPort,
16
+ outputDir,
17
+ capabilities
18
+ )
14
19
  );
15
20
  return [this.endpoint];
16
21
  }
17
22
 
18
- generateExtensionsHandler(baseMessage, webSocketPort, outputDir) {
23
+ generateExtensionsHandler(
24
+ baseMessage,
25
+ webSocketPort,
26
+ outputDir,
27
+ capabilities = []
28
+ ) {
19
29
  return function extensionsHandler(_req, res) {
20
30
  try {
21
31
  const output = path.parse(baseMessage.callback).name;
@@ -23,6 +33,7 @@ class ExtensionsService {
23
33
  const response = {
24
34
  websocket: `ws://localhost:${webSocketPort}`,
25
35
  version: EXTENSIONS_MESSAGE_VERSION,
36
+ capabilities,
26
37
  extensions: [
27
38
  {
28
39
  ...baseMessage,
@@ -0,0 +1,30 @@
1
+ const path = require('path');
2
+
3
+ function codeInjectionPlugin(options = {}) {
4
+ const { file, root = process.cwd() } = options;
5
+ return {
6
+ name: 'ui-extensions-code-injection-plugin',
7
+ enforce: 'post', // run after default rollup plugins
8
+ transform(code, fileBeingTransformed) {
9
+ const absoluteFilePath = path.isAbsolute(file)
10
+ ? file
11
+ : path.join(root, file);
12
+
13
+ if (fileBeingTransformed !== absoluteFilePath) {
14
+ return { code, map: null }; // Not the file we care about, return the same code
15
+ }
16
+
17
+ // Update the code to import the self script which houses our overrides
18
+ // This needs to be the first line in the source file so that the overrides get hoisted
19
+ // to the top of the generated source file
20
+ const updatedCode = `import "@hubspot/ui-extensions-dev-server/self"; ${code}`;
21
+
22
+ // Return the updated source code. We don't need to include the new code in the
23
+ // sourcemap because we don't want it to show up in the users code when they
24
+ // view the source mapped code in the browser
25
+ return { code: updatedCode, map: null };
26
+ },
27
+ };
28
+ }
29
+
30
+ module.exports = codeInjectionPlugin;
@@ -2,6 +2,7 @@ const { ROLLUP_OPTIONS, WEBSOCKET_MESSAGE_VERSION } = require('../constants');
2
2
  const { build } = require('vite');
3
3
  const manifestPlugin = require('./manifestPlugin');
4
4
  const { stripAnsiColorCodes } = require('../utils');
5
+ const codeInjectionPlugin = require('./codeInjectionPlugin');
5
6
 
6
7
  function devBuildPlugin(options = {}) {
7
8
  const { extensionConfig, outputDir, baseMessage, logger } = options;
@@ -36,6 +37,7 @@ function devBuildPlugin(options = {}) {
36
37
  const devBuild = async server => {
37
38
  try {
38
39
  await build({
40
+ logLevel: 'warn',
39
41
  mode: 'development',
40
42
  define: {
41
43
  'process.env.NODE_ENV': JSON.stringify(
@@ -57,6 +59,7 @@ function devBuildPlugin(options = {}) {
57
59
  output: extensionConfig.output,
58
60
  logger,
59
61
  }),
62
+ codeInjectionPlugin({ file: extensionConfig.data.module.file }),
60
63
  ],
61
64
  output: {
62
65
  ...ROLLUP_OPTIONS.output,
@@ -71,6 +74,7 @@ function devBuildPlugin(options = {}) {
71
74
  });
72
75
  return true;
73
76
  } catch (error) {
77
+ logger.error(error);
74
78
  handleBuildError(error, server);
75
79
  return false;
76
80
  }
@@ -111,7 +115,7 @@ function devBuildPlugin(options = {}) {
111
115
  }
112
116
 
113
117
  if (server.ws.clients.size === 0) {
114
- logger.info('Bundle updated, no browsers connected to notify');
118
+ logger.warn('Bundle updated, no browsers connected to notify');
115
119
  return [];
116
120
  }
117
121
 
package/lib/self.js ADDED
@@ -0,0 +1,4 @@
1
+ /* eslint-disable hubspot-dev/no-confusing-browser-globals */
2
+
3
+ // Set methods on the self object to undefined so they are not available within the worker code
4
+ self.importScripts = undefined;
package/lib/server.js CHANGED
@@ -1,36 +1,53 @@
1
1
  const express = require('express');
2
2
  const cors = require('cors');
3
+ const { SERVER_CAPABILITIES } = require('./constants');
3
4
  const extensionsService = require('./extensionsService');
5
+ const {
6
+ AppFunctionExecutionService,
7
+ } = require('@hubspot/app-functions-dev-server');
4
8
 
5
- function startDevServer(
9
+ function startDevServer({
6
10
  outputDir,
7
11
  expressPort,
8
12
  webSocketPort,
9
13
  baseMessage,
10
14
  viteDevServer,
11
- logger
12
- ) {
15
+ functionsConfig,
16
+ logger,
17
+ }) {
13
18
  const app = express();
14
19
 
15
20
  // Setup middleware
16
21
  app.use(cors());
17
22
  app.use(express.static(outputDir));
23
+
24
+ const capabilities = functionsConfig.enabled ? SERVER_CAPABILITIES : [];
25
+
26
+ if (functionsConfig.enabled) {
27
+ app.use(
28
+ '/api/crm-extensibility/execution/internal/v3',
29
+ AppFunctionExecutionService({ ...functionsConfig, logger })
30
+ );
31
+ logger.info('Serving app functions locally');
32
+ }
33
+
18
34
  const endpointsAdded = extensionsService.add(
19
35
  app,
20
36
  webSocketPort,
21
37
  outputDir,
22
- baseMessage
38
+ baseMessage,
39
+ capabilities
23
40
  );
24
41
 
25
42
  endpointsAdded.forEach(endpoint => {
26
- logger.info(`Listening at http://hslocal.net:${expressPort}${endpoint}`);
43
+ logger.debug(`Listening at http://hslocal.net:${expressPort}${endpoint}`);
27
44
  });
28
45
 
29
46
  // Vite middlewares needs to go last because it's greedy and will block other middleware
30
47
  app.use(viteDevServer.middlewares);
31
48
 
32
49
  const server = app.listen({ port: expressPort }, () => {
33
- logger.info(`Listening at ${baseMessage.callback}`);
50
+ logger.debug(`Listening at ${baseMessage.callback}`);
34
51
  });
35
52
 
36
53
  return async function shutdown() {
@@ -38,7 +55,6 @@ function startDevServer(
38
55
  // Stop new connections to express server
39
56
  server.close(() => {});
40
57
  logger.info('Clean up done, exiting.');
41
- process.exit(0);
42
58
  };
43
59
  }
44
60
 
package/lib/utils.js CHANGED
@@ -8,8 +8,11 @@ function getUrlSafeFileName(filePath) {
8
8
  }
9
9
 
10
10
  // Strips ANSI color codes out of strings because we don't want to pass them to the browser
11
- function stripAnsiColorCodes(string) {
12
- return string.replace(
11
+ function stripAnsiColorCodes(stringWithColorCodes) {
12
+ if (!stringWithColorCodes) {
13
+ return null;
14
+ }
15
+ return stringWithColorCodes.replace(
13
16
  // eslint-disable-next-line no-control-regex
14
17
  /[\u001b][[]*([0-9]{1,4};?)*[m]/g,
15
18
  ''
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions-dev-server",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -10,12 +10,14 @@
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
13
+ "exports": {
14
+ ".": "./index.js",
15
+ "./self": "./lib/self.js"
16
+ },
13
17
  "files": [
14
18
  "cli/config.js",
15
- "cli/extensions.js",
16
19
  "cli/logger.js",
17
20
  "cli/run.js",
18
- "cli/userInput.js",
19
21
  "cli/utils.js",
20
22
  "lib/plugins/*",
21
23
  "lib/build.js",
@@ -23,6 +25,7 @@
23
25
  "lib/dev.js",
24
26
  "lib/extensionsService.js",
25
27
  "lib/DevModeInterface.js",
28
+ "lib/self.js",
26
29
  "lib/server.js",
27
30
  "lib/utils.js",
28
31
  "index.js",
@@ -30,12 +33,13 @@
30
33
  ],
31
34
  "license": "MIT",
32
35
  "dependencies": {
36
+ "@hubspot/app-functions-dev-server": "^0.6.0",
33
37
  "command-line-args": "^5.2.1",
34
38
  "command-line-usage": "^7.0.1",
35
39
  "console-log-colors": "^0.4.0",
36
40
  "cors": "^2.8.5",
37
41
  "express": "^4.18.2",
38
- "prompts": "^2.4.2",
42
+ "inquirer": "8.2.0",
39
43
  "vite": "^4.0.4"
40
44
  },
41
45
  "devDependencies": {
@@ -63,5 +67,5 @@
63
67
  "optional": true
64
68
  }
65
69
  },
66
- "gitHead": "1269fb86282dd5f6b9686d064b6c652f00cb863f"
70
+ "gitHead": "1979c2dce0a920c10e4f8b5ec3bc16a1080120cb"
67
71
  }
package/cli/extensions.js DELETED
@@ -1,9 +0,0 @@
1
- const { loadConfig } = require('./config');
2
-
3
- function getExtensionsList() {
4
- return Object.keys(loadConfig());
5
- }
6
-
7
- module.exports = {
8
- getExtensionsList,
9
- };
package/cli/userInput.js DELETED
@@ -1,33 +0,0 @@
1
- const prompts = require('prompts');
2
- const path = require('path');
3
-
4
- const { getExtensionsList } = require('./extensions');
5
-
6
- async function promptForExtensionToRun() {
7
- const extensionOptions = getExtensionsList();
8
- const response = await prompts(
9
- [
10
- {
11
- type: 'select',
12
- name: 'extension',
13
- message: 'Which extension would you like to run?',
14
- choices: extensionOptions.map(option => {
15
- return {
16
- title: option,
17
- value: option,
18
- };
19
- }),
20
- },
21
- ],
22
- {
23
- onCancel: () => {
24
- process.exit(0); // When the user cancels interaction, exit the script
25
- },
26
- }
27
- );
28
- return path.parse(response.extension).name;
29
- }
30
-
31
- module.exports = {
32
- promptForExtensionToRun,
33
- };