@hubspot/ui-extensions-dev-server 0.8.4 → 0.8.7

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.
@@ -18,6 +18,12 @@ interface StartArguments {
18
18
  accountId?: number;
19
19
  debug?: boolean;
20
20
  httpClient?: ServiceConfiguration['httpClient'];
21
+ requestPorts?: (requestPortsData: Array<{
22
+ instanceId: string;
23
+ port?: number;
24
+ }>) => Promise<{
25
+ [instanceId: string]: number;
26
+ }>;
21
27
  projectConfig?: ProjectConfig;
22
28
  }
23
29
  interface AppExtensionMapping {
@@ -33,7 +39,7 @@ declare class DevModeInterface {
33
39
  _getPlatformVersion(projectConfig?: ProjectConfig): PlatformVersion;
34
40
  setup({ components, debug, extensionConfig, onUploadRequired, promptUser, }: SetupArguments): Promise<void>;
35
41
  fileChange(filePath: string, __event: unknown): Promise<void>;
36
- start({ accountId, debug, httpClient, projectConfig }: StartArguments): Promise<void>;
42
+ start({ requestPorts, accountId, debug, httpClient, projectConfig, }: StartArguments): Promise<void>;
37
43
  cleanup(): Promise<void>;
38
44
  }
39
45
  declare const _default: DevModeInterface;
@@ -13,6 +13,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  const dev_1 = require("./dev");
15
15
  const constants_1 = require("./constants");
16
+ const constants_2 = require("./constants");
16
17
  const config_1 = require("./config");
17
18
  // @ts-expect-error no type defs
18
19
  const logger_1 = require("@hubspot/cli-lib/logger");
@@ -32,7 +33,7 @@ class DevModeInterface {
32
33
  const extensionsConfigForApp = (0, config_1.loadExtensionConfig)(component.config, component.path);
33
34
  const extensionConfigKeys = Object.keys(extensionsConfigForApp);
34
35
  // Loop over the loaded extension configs and generate the list of choices to use to prompt the user for input
35
- extensionConfigKeys.forEach(extensionKey => {
36
+ extensionConfigKeys.forEach((extensionKey) => {
36
37
  const extensionConfig = extensionsConfigForApp[extensionKey];
37
38
  appExtensionMappings.push({
38
39
  name: `${componentName}/${extensionConfig.data.title}`,
@@ -45,13 +46,13 @@ class DevModeInterface {
45
46
  _getPlatformVersion(projectConfig) {
46
47
  const { platformVersion } = projectConfig !== null && projectConfig !== void 0 ? projectConfig : {};
47
48
  if (!platformVersion) {
48
- return constants_1.PLATFORM_VERSION.V20231;
49
+ return constants_2.PLATFORM_VERSION.V20231;
49
50
  }
50
51
  switch (platformVersion) {
51
- case constants_1.PLATFORM_VERSION.V20231:
52
- return constants_1.PLATFORM_VERSION.V20231;
53
- case constants_1.PLATFORM_VERSION.V20232:
54
- return constants_1.PLATFORM_VERSION.V20232;
52
+ case constants_2.PLATFORM_VERSION.V20231:
53
+ return constants_2.PLATFORM_VERSION.V20231;
54
+ case constants_2.PLATFORM_VERSION.V20232:
55
+ return constants_2.PLATFORM_VERSION.V20232;
55
56
  default:
56
57
  return (0, utils_1.throwUnhandledPlatformVersionError)(platformVersion);
57
58
  }
@@ -76,10 +77,14 @@ class DevModeInterface {
76
77
  type: 'checkbox',
77
78
  name: 'extensions',
78
79
  message: 'Which extension(s) would you like to run?',
79
- validate: input => {
80
+ validate: (input) => {
80
81
  if (!input || input.length === 0) {
81
82
  return 'Select at least one extension to run';
82
83
  }
84
+ const appNames = new Set(input.map((choice) => choice.data.appName));
85
+ if (appNames.size > 1) {
86
+ return 'Running multiple extensions is only supported for a single application';
87
+ }
83
88
  return true;
84
89
  },
85
90
  choices,
@@ -95,25 +100,42 @@ class DevModeInterface {
95
100
  if (!this.devServerState || !this.devServerState.extensionsMetadata) {
96
101
  return;
97
102
  }
98
- const relevantConfigFileChanged = this.devServerState.extensionsMetadata.some(metadata => metadata.config.extensionConfigPath === filePath);
103
+ const relevantConfigFileChanged = this.devServerState.extensionsMetadata.some((metadata) => metadata.config.extensionConfigPath === filePath);
99
104
  if (relevantConfigFileChanged && this.onUploadRequired) {
100
105
  this.onUploadRequired();
101
106
  }
102
107
  });
103
108
  }
104
- start({ accountId, debug, httpClient, projectConfig }) {
109
+ start({ requestPorts, accountId, debug, httpClient, projectConfig, }) {
105
110
  return __awaiter(this, void 0, void 0, function* () {
106
111
  if (debug !== undefined) {
107
112
  (0, logger_1.setLogLevel)(debug ? logger_1.LOG_LEVEL.DEBUG : logger_1.LOG_LEVEL.LOG);
108
113
  }
114
+ let expressPort = constants_1.EXPRESS_DEFAULT_PORT;
115
+ let webSocketPort = constants_1.WEBSOCKET_DEFAULT_PORT;
116
+ if (requestPorts) {
117
+ try {
118
+ const portData = yield requestPorts([
119
+ { instanceId: constants_1.EXPRESS_SERVER_ID, port: constants_1.EXPRESS_DEFAULT_PORT },
120
+ { instanceId: constants_1.VITE_DEV_SERVER_ID, port: constants_1.WEBSOCKET_DEFAULT_PORT },
121
+ ]);
122
+ expressPort = portData[constants_1.EXPRESS_SERVER_ID];
123
+ webSocketPort = portData[constants_1.VITE_DEV_SERVER_ID];
124
+ }
125
+ catch (e) {
126
+ logger_1.logger.debug('Call to port manager failed, using default ports');
127
+ }
128
+ }
109
129
  this.devServerState = new DevServerState_1.DevServerState({
110
130
  extensionConfigs: this.configs,
111
131
  accountId,
112
132
  httpClient,
113
133
  platformVersion: this._getPlatformVersion(projectConfig),
134
+ expressPort,
135
+ webSocketPort,
114
136
  });
115
137
  this.shutdown = yield (0, dev_1.startDevMode)(this.devServerState);
116
- this.devServerState.extensionsMetadata.forEach(metadata => {
138
+ this.devServerState.extensionsMetadata.forEach((metadata) => {
117
139
  const { config: { data: { title, appName }, }, } = metadata;
118
140
  logger_1.logger.info(`Running extension '${title}' from app '${appName}'`);
119
141
  });
@@ -4,8 +4,8 @@ interface DevServerStateArgs {
4
4
  extensionConfigs?: ExtensionConfig[];
5
5
  accountId: number | undefined;
6
6
  httpClient: ServiceConfiguration['httpClient'] | undefined;
7
- expressPort?: number;
8
- webSocketPort?: number;
7
+ expressPort: number;
8
+ webSocketPort: number;
9
9
  platformVersion: PlatformVersion;
10
10
  }
11
11
  export declare class DevServerState {
@@ -7,14 +7,12 @@ exports.DevServerState = void 0;
7
7
  const constants_1 = require("./constants");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  class DevServerState {
10
- constructor({ extensionConfigs, accountId, httpClient, expressPort = constants_1.VITE_DEFAULT_PORT, webSocketPort = constants_1.WEBSOCKET_PORT, platformVersion, }) {
11
- this._webSocketPort = constants_1.WEBSOCKET_PORT;
12
- this._expressPort = constants_1.VITE_DEFAULT_PORT;
10
+ constructor({ extensionConfigs, accountId, httpClient, expressPort, webSocketPort, platformVersion, }) {
13
11
  if (!extensionConfigs) {
14
12
  throw new Error('Unable to load the required extension configuration files');
15
13
  }
16
14
  const extensionsMetadata = [];
17
- extensionConfigs.forEach(config => {
15
+ extensionConfigs.forEach((config) => {
18
16
  const { appName, title, sourceId } = config.data;
19
17
  extensionsMetadata.push({
20
18
  config,
@@ -0,0 +1,5 @@
1
+ import { SourceCodeChecks } from './types';
2
+ import { Program } from 'estree';
3
+ export declare function traverseAbstractSyntaxTree(ast: Program, checks: SourceCodeChecks): {
4
+ functions: {};
5
+ };
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ /* eslint-disable hubspot-dev/no-unsupported-ts-syntax */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.traverseAbstractSyntaxTree = void 0;
5
+ // @ts-expect-error no type defs
6
+ const estraverse_1 = require("estraverse");
7
+ function _isVariableImported(node, variableName) {
8
+ if (!node) {
9
+ return false;
10
+ }
11
+ return ((node.type === 'ImportSpecifier' && node.imported.name === variableName) ||
12
+ (node.type === 'ImportDefaultSpecifier' &&
13
+ node.local.name === variableName) ||
14
+ (node.type === 'ImportNamespaceSpecifier' &&
15
+ node.local.name === variableName));
16
+ }
17
+ function _isIdentifierDefined(node, parent, name) {
18
+ if (parent &&
19
+ (parent.type === 'MemberExpression' || parent.type === 'CallExpression')) {
20
+ return false;
21
+ }
22
+ return node.type === 'Identifier' && node.name === name;
23
+ }
24
+ function _isFunctionInvoked(node, functionName) {
25
+ return (node.type === 'CallExpression' &&
26
+ node.callee &&
27
+ 'name' in node.callee &&
28
+ node.callee.name === functionName);
29
+ }
30
+ function _checkForFunctionMetadata(node, parent, output, functionName) {
31
+ if (!node) {
32
+ return;
33
+ }
34
+ if (!output.functions[functionName]) {
35
+ output.functions[functionName] = {};
36
+ }
37
+ if (_isFunctionInvoked(node, functionName)) {
38
+ output.functions[functionName].invoked = true;
39
+ // If the function is invoked before being defined we will assume it is a global function
40
+ output.functions[functionName].scope = output.functions[functionName]
41
+ .defined
42
+ ? 'Local'
43
+ : 'Global';
44
+ }
45
+ else if (_isIdentifierDefined(node, parent, functionName) ||
46
+ _isVariableImported(node, functionName)) {
47
+ output.functions[functionName].defined = true;
48
+ }
49
+ }
50
+ // Traverses an ESTree as defined by the EsTree spec https://github.com/estree/estree
51
+ // Uses the checks array to search the source code for matches
52
+ function traverseAbstractSyntaxTree(ast, checks) {
53
+ const state = {
54
+ functions: {},
55
+ };
56
+ (0, estraverse_1.traverse)(ast, {
57
+ enter(node, parent) {
58
+ checks.forEach((check) => {
59
+ _checkForFunctionMetadata(node, parent, state, check.functionName);
60
+ });
61
+ },
62
+ });
63
+ return state;
64
+ }
65
+ exports.traverseAbstractSyntaxTree = traverseAbstractSyntaxTree;
package/dist/lib/build.js CHANGED
@@ -19,6 +19,7 @@ const manifestPlugin_1 = __importDefault(require("./plugins/manifestPlugin"));
19
19
  const path_1 = __importDefault(require("path"));
20
20
  const utils_1 = require("./utils");
21
21
  const codeInjectionPlugin_1 = __importDefault(require("./plugins/codeInjectionPlugin"));
22
+ const codeBlockingPlugin_1 = __importDefault(require("./plugins/codeBlockingPlugin"));
22
23
  const allowedExtensions = ['.js', '.ts', '.tsx', '.jsx'];
23
24
  exports.extensionErrorBaseMessage = `Supported file extensions are [${allowedExtensions.join(', ')}], received:`;
24
25
  function buildSingleExtension({ file, outputDir = constants_1.OUTPUT_DIR, emptyOutDir = true, minify = false, root = process.cwd(), // This is the vite default, so using that as our default
@@ -40,6 +41,7 @@ function buildSingleExtension({ file, outputDir = constants_1.OUTPUT_DIR, emptyO
40
41
  rollupOptions: Object.assign(Object.assign({}, constants_1.ROLLUP_OPTIONS), { plugins: [
41
42
  (0, manifestPlugin_1.default)({ output, extensionPath: root }),
42
43
  (0, codeInjectionPlugin_1.default)({ file }),
44
+ (0, codeBlockingPlugin_1.default)(),
43
45
  ] }),
44
46
  outDir: outputDir,
45
47
  emptyOutDir,
@@ -18,7 +18,7 @@ function loadExtensionConfig(appConfig, appPath) {
18
18
  var _a, _b;
19
19
  const crmCardsSubConfigFiles = (_b = (_a = appConfig === null || appConfig === void 0 ? void 0 : appConfig.extensions) === null || _a === void 0 ? void 0 : _a.crm) === null || _b === void 0 ? void 0 : _b.cards;
20
20
  const outputConfig = {};
21
- crmCardsSubConfigFiles.forEach(card => {
21
+ crmCardsSubConfigFiles.forEach((card) => {
22
22
  var _a, _b;
23
23
  const cardConfigPath = path_1.default.join(appPath, card.file);
24
24
  try {
@@ -1,8 +1,10 @@
1
1
  export declare const OUTPUT_DIR = "dist";
2
2
  export declare const MAIN_APP_CONFIG = "app.json";
3
3
  export declare const MANIFEST_FILE = "manifest.json";
4
- export declare const VITE_DEFAULT_PORT = 5173;
5
- export declare const WEBSOCKET_PORT = 5174;
4
+ export declare const EXPRESS_SERVER_ID = "ui-extensions-dev-server";
5
+ export declare const VITE_DEV_SERVER_ID = "ui-extensions-vite-dev-server";
6
+ export declare const EXPRESS_DEFAULT_PORT = 5173;
7
+ export declare const WEBSOCKET_DEFAULT_PORT = 5174;
6
8
  export declare const ROLLUP_OPTIONS: {
7
9
  external: string[];
8
10
  output: {
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PLATFORM_VERSION = exports.SERVER_CAPABILITIES = exports.WEBSOCKET_MESSAGE_VERSION = exports.EXTENSIONS_MESSAGE_VERSION = exports.ROLLUP_OPTIONS = exports.WEBSOCKET_PORT = exports.VITE_DEFAULT_PORT = exports.MANIFEST_FILE = exports.MAIN_APP_CONFIG = exports.OUTPUT_DIR = void 0;
3
+ exports.PLATFORM_VERSION = exports.SERVER_CAPABILITIES = exports.WEBSOCKET_MESSAGE_VERSION = exports.EXTENSIONS_MESSAGE_VERSION = exports.ROLLUP_OPTIONS = exports.WEBSOCKET_DEFAULT_PORT = exports.EXPRESS_DEFAULT_PORT = exports.VITE_DEV_SERVER_ID = exports.EXPRESS_SERVER_ID = exports.MANIFEST_FILE = exports.MAIN_APP_CONFIG = exports.OUTPUT_DIR = void 0;
4
4
  exports.OUTPUT_DIR = 'dist';
5
5
  exports.MAIN_APP_CONFIG = 'app.json';
6
6
  exports.MANIFEST_FILE = 'manifest.json';
7
- exports.VITE_DEFAULT_PORT = 5173;
8
- exports.WEBSOCKET_PORT = 5174;
7
+ exports.EXPRESS_SERVER_ID = 'ui-extensions-dev-server';
8
+ exports.VITE_DEV_SERVER_ID = 'ui-extensions-vite-dev-server';
9
+ exports.EXPRESS_DEFAULT_PORT = 5173;
10
+ exports.WEBSOCKET_DEFAULT_PORT = 5174;
9
11
  exports.ROLLUP_OPTIONS = {
10
12
  // Deps to exclude from the bundle
11
13
  external: ['react', 'react-dom', '@remote-ui/react'],
package/dist/lib/dev.js CHANGED
@@ -18,8 +18,6 @@ const path_1 = __importDefault(require("path"));
18
18
  const server_1 = __importDefault(require("./server"));
19
19
  const devBuildPlugin_1 = __importDefault(require("./plugins/devBuildPlugin"));
20
20
  // @ts-expect-error no type defs
21
- const logger_1 = require("@hubspot/cli-lib/logger");
22
- // @ts-expect-error no type defs
23
21
  const detect_port_1 = __importDefault(require("detect-port"));
24
22
  function _createViteDevServer(devServerState) {
25
23
  return __awaiter(this, void 0, void 0, function* () {
@@ -66,12 +64,7 @@ function startDevMode(devServerState) {
66
64
  if (!devServerState || !devServerState.extensionsMetadata) {
67
65
  throw new Error('Unable to determine which extension to run');
68
66
  }
69
- const { expressPort, webSocketPort } = devServerState;
70
- yield throwIfPortTaken(expressPort);
71
- const actualWebSocketPort = yield (0, detect_port_1.default)(webSocketPort);
72
- if (actualWebSocketPort !== webSocketPort) {
73
- logger_1.logger.debug(`WebSocket port ${webSocketPort} is in use; using next available port ${actualWebSocketPort}`);
74
- }
67
+ yield throwIfPortTaken(devServerState.webSocketPort);
75
68
  const viteDevServer = yield _createViteDevServer(devServerState);
76
69
  const shutdownServer = yield (0, server_1.default)({
77
70
  devServerState,
@@ -18,7 +18,7 @@ class ExtensionsService {
18
18
  generateExtensionsHandler(devServerState, capabilities = []) {
19
19
  return function extensionsHandler(_req, res) {
20
20
  try {
21
- const extensions = devServerState.extensionsMetadata.map(metadata => {
21
+ const extensions = devServerState.extensionsMetadata.map((metadata) => {
22
22
  const { baseMessage } = metadata;
23
23
  const output = path_1.default.parse(baseMessage.callback).name;
24
24
  return Object.assign(Object.assign({}, baseMessage), { manifest: (0, utils_1.loadManifest)(devServerState.outputDir, output) });
@@ -0,0 +1,4 @@
1
+ import { Rollup } from 'vite';
2
+ export type CodeBlockingPlugin = () => Rollup.Plugin;
3
+ declare const codeBlockingPlugin: CodeBlockingPlugin;
4
+ export default codeBlockingPlugin;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /* eslint-disable hubspot-dev/no-unsupported-ts-syntax */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const utils_1 = require("../utils");
5
+ const ast_1 = require("../ast");
6
+ // @ts-expect-error no types
7
+ const logger_1 = require("@hubspot/cli-lib/logger");
8
+ const codeBlockingPlugin = () => {
9
+ return {
10
+ name: 'ui-extensions-code-blocking-plugin',
11
+ enforce: 'post',
12
+ transform(code, filename) {
13
+ if ((0, utils_1.isNodeModule)(filename)) {
14
+ return { code, map: null }; // We don't want to parse node modules
15
+ }
16
+ let sourceCodeMetadata = { functions: {} };
17
+ const requireFunctionName = 'require';
18
+ try {
19
+ // Not sure why the types don't match for this.parse and the Rollup docs, but
20
+ // the docs over on rollup's site specify ESTree.Program as the return type,
21
+ // and the underlying data matches that https://rollupjs.org/plugin-development/#this-parse
22
+ const abstractSyntaxTree = this.parse(code);
23
+ sourceCodeMetadata = (0, ast_1.traverseAbstractSyntaxTree)(abstractSyntaxTree, [
24
+ { functionName: requireFunctionName },
25
+ ]);
26
+ }
27
+ catch (e) {
28
+ logger_1.logger.debug('Unable to parse and traverse source code');
29
+ return { code, map: null };
30
+ }
31
+ if (sourceCodeMetadata.functions[requireFunctionName] &&
32
+ sourceCodeMetadata.functions[requireFunctionName].scope === 'Global') {
33
+ logger_1.logger.warn('require statements are not supported, replace require statements with import');
34
+ }
35
+ return { code, map: null };
36
+ },
37
+ };
38
+ };
39
+ exports.default = codeBlockingPlugin;
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const fs_1 = __importDefault(require("fs"));
7
7
  // @ts-expect-error no type defs for the logger
8
8
  const logger_1 = require("@hubspot/cli-lib/logger");
9
- const codeCheckingPlugin = options => {
9
+ const codeCheckingPlugin = (options) => {
10
10
  const { output } = options;
11
11
  return {
12
12
  name: 'ui-extensions-code-checking-plugin',
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const path_1 = __importDefault(require("path"));
7
- const codeInjectionPlugin = options => {
7
+ const codeInjectionPlugin = (options) => {
8
8
  const { file, root = process.cwd() } = options;
9
9
  return {
10
10
  name: 'ui-extensions-code-injection-plugin',
@@ -47,10 +47,11 @@ const path_1 = __importDefault(require("path"));
47
47
  const logger_1 = require("@hubspot/cli-lib/logger");
48
48
  const friendlyLoggingPlugin_1 = __importDefault(require("./friendlyLoggingPlugin"));
49
49
  const relevantModulesPlugin_1 = __importStar(require("./relevantModulesPlugin"));
50
+ const codeBlockingPlugin_1 = __importDefault(require("./codeBlockingPlugin"));
50
51
  function addVersionToBaseMessage(baseMessage) {
51
52
  return Object.assign(Object.assign({}, baseMessage), { version: constants_1.WEBSOCKET_MESSAGE_VERSION });
52
53
  }
53
- const devBuildPlugin = options => {
54
+ const devBuildPlugin = (options) => {
54
55
  const { devServerState } = options;
55
56
  let lastBuildErrorContext;
56
57
  const handleBuildError = (error, server) => {
@@ -102,6 +103,7 @@ const devBuildPlugin = options => {
102
103
  }),
103
104
  (0, friendlyLoggingPlugin_1.default)(),
104
105
  (0, relevantModulesPlugin_1.default)({ output: extensionConfig.output }),
106
+ (0, codeBlockingPlugin_1.default)(),
105
107
  ], output: Object.assign(Object.assign({}, constants_1.ROLLUP_OPTIONS.output), { sourcemap: 'inline' }) }),
106
108
  outDir: devServerState.outputDir,
107
109
  emptyOutDir,
@@ -132,7 +134,7 @@ const devBuildPlugin = options => {
132
134
  localServer = server;
133
135
  localServer.ws.on('connection', () => {
134
136
  logger_1.logger.info('Browser connected and listening for bundle updates');
135
- devServerState.extensionsMetadata.forEach(metadata => {
137
+ devServerState.extensionsMetadata.forEach((metadata) => {
136
138
  // @ts-expect-error Our websocket messages don't match Vite format
137
139
  localServer.ws.send(Object.assign(Object.assign({}, addVersionToBaseMessage(metadata.baseMessage)), { event: 'start' }));
138
140
  });
@@ -146,7 +148,7 @@ const devBuildPlugin = options => {
146
148
  }),
147
149
  handleHotUpdate: ({ file, server }) => __awaiter(void 0, void 0, void 0, function* () {
148
150
  // If the file is not in the relevantModules list, it's update is inconsequential
149
- const extensionsToRebuild = devServerState.extensionsMetadata.filter(metadata => {
151
+ const extensionsToRebuild = devServerState.extensionsMetadata.filter((metadata) => {
150
152
  const { config } = metadata;
151
153
  return (0, relevantModulesPlugin_1.getRelevantModules)(config.output).includes(file);
152
154
  });
@@ -174,7 +176,7 @@ const devBuildPlugin = options => {
174
176
  }
175
177
  if (localServer && localServer.ws) {
176
178
  logger_1.logger.debug('Sending shutdown message to connected browsers');
177
- devServerState.extensionsMetadata.forEach(metadata => {
179
+ devServerState.extensionsMetadata.forEach((metadata) => {
178
180
  // @ts-expect-error Our websocket messages don't match Vite format
179
181
  localServer.ws.send(Object.assign(Object.assign({}, addVersionToBaseMessage(metadata.baseMessage)), { event: 'shutdown' }));
180
182
  });
@@ -15,7 +15,7 @@ const utils_1 = require("../utils");
15
15
  const PACKAGE_LOCK_FILE = 'package-lock.json';
16
16
  const PACKAGE_FILE = 'package.json';
17
17
  const EXTENSIONS_PATH = 'src/app/extensions/';
18
- const manifestPlugin = options => {
18
+ const manifestPlugin = (options) => {
19
19
  return {
20
20
  name: 'ui-extensions-manifest-generation-plugin',
21
21
  enforce: 'post',
@@ -43,7 +43,7 @@ function _generateManifestContents(bundle, extensionPath) {
43
43
  package: _loadPackageFile(extensionPath),
44
44
  };
45
45
  // The keys to bundle are the filename without any path information
46
- const bundles = Object.keys(bundle).filter(cur => cur.endsWith('.js'));
46
+ const bundles = Object.keys(bundle).filter((cur) => cur.endsWith('.js'));
47
47
  if (bundles.length === 1) {
48
48
  return Object.assign(Object.assign({}, _generateManifestEntry(bundle[bundles[0]])), baseManifest);
49
49
  }
@@ -19,7 +19,7 @@ const relevantModulesPlugin = ({ output }) => {
19
19
  logger_1.logger.error('Invalid bundle format, please try saving the extension again. If the problem persists try restarting `hs project dev`');
20
20
  return;
21
21
  }
22
- const updatedRelevantModules = subBundle.moduleIds.filter(moduleId => !(0, utils_1.isNodeModule)(moduleId));
22
+ const updatedRelevantModules = subBundle.moduleIds.filter((moduleId) => !(0, utils_1.isNodeModule)(moduleId));
23
23
  if (updatedRelevantModules.length === 0) {
24
24
  logger_1.logger.error('Unable to determine relevant files to watch, please try saving the extension again. If the problem persists try restarting `hs project dev`');
25
25
  return;
@@ -27,7 +27,7 @@ function listen(app, port) {
27
27
  .listen({ port }, () => {
28
28
  resolve(server);
29
29
  })
30
- .on('error', err => {
30
+ .on('error', (err) => {
31
31
  reject(err);
32
32
  });
33
33
  });
@@ -43,7 +43,7 @@ function startDevServer({ devServerState, viteDevServer, }) {
43
43
  logger_1.logger.info(`Serving app functions locally (platform version ${devServerState.functionsConfig.platformVersion})`);
44
44
  const endpointsAdded = extensionsService_1.default.add(app, devServerState, constants_1.SERVER_CAPABILITIES);
45
45
  const { expressPort } = devServerState;
46
- endpointsAdded.forEach(endpoint => {
46
+ endpointsAdded.forEach((endpoint) => {
47
47
  logger_1.logger.debug(`Listening at http://hslocal.net:${expressPort}${endpoint}`);
48
48
  });
49
49
  // Vite middlewares needs to go last because it's greedy and will block other middleware
@@ -58,7 +58,7 @@ function startDevServer({ devServerState, viteDevServer, }) {
58
58
  }
59
59
  throw new Error(e);
60
60
  }
61
- (_a = devServerState.extensionsMetadata) === null || _a === void 0 ? void 0 : _a.forEach(metadata => {
61
+ (_a = devServerState.extensionsMetadata) === null || _a === void 0 ? void 0 : _a.forEach((metadata) => {
62
62
  const { baseMessage } = metadata;
63
63
  logger_1.logger.debug(`Listening at ${baseMessage.callback}`);
64
64
  });
@@ -56,5 +56,19 @@ export interface ExtensionMetadata {
56
56
  baseMessage: BaseMessage;
57
57
  config: ExtensionConfig;
58
58
  }
59
- export type PlatformVersion = typeof PLATFORM_VERSION[keyof typeof PLATFORM_VERSION];
59
+ export type PlatformVersion = (typeof PLATFORM_VERSION)[keyof typeof PLATFORM_VERSION];
60
+ export interface FunctionMetadata {
61
+ scope?: 'Global' | 'Local';
62
+ defined?: boolean;
63
+ invoked?: boolean;
64
+ }
65
+ export interface SourceCodeMetadata {
66
+ functions: {
67
+ [functionName: string]: FunctionMetadata;
68
+ };
69
+ }
70
+ export interface FunctionInvocationCheck {
71
+ functionName: string;
72
+ }
73
+ export type SourceCodeChecks = FunctionInvocationCheck[];
60
74
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions-dev-server",
3
- "version": "0.8.4",
3
+ "version": "0.8.7",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "jest",
@@ -9,7 +9,8 @@
9
9
  "watch": "npm run clean && tsc --watch",
10
10
  "prepare": "npm run build",
11
11
  "lint": "echo 'no lint step for @hubspot/ui-extensions-dev-server'",
12
- "jest": "jest --watch"
12
+ "jest": "jest --watch",
13
+ "integration-test": "npm run build && npm run integration-test --prefix ./integrationTests/fixtures"
13
14
  },
14
15
  "publishConfig": {
15
16
  "access": "public"
@@ -24,21 +25,24 @@
24
25
  ],
25
26
  "license": "MIT",
26
27
  "dependencies": {
27
- "@hubspot/app-functions-dev-server": "^0.8.3",
28
+ "@hubspot/app-functions-dev-server": "^0.8.7",
28
29
  "@hubspot/cli-lib": "^4.1.6",
29
30
  "command-line-args": "^5.2.1",
30
31
  "command-line-usage": "^7.0.1",
31
32
  "console-log-colors": "^0.4.0",
32
33
  "cors": "^2.8.5",
33
34
  "detect-port": "1.5.1",
35
+ "estraverse": "^5.3.0",
34
36
  "express": "^4.18.2",
35
37
  "inquirer": "8.2.0",
36
38
  "vite": "^4.4.9"
37
39
  },
38
40
  "devDependencies": {
41
+ "@types/estree": "^1.0.5",
39
42
  "@types/express": "types/express",
40
43
  "@types/inquirer": "^9.0.3",
41
44
  "@types/jest": "^29.5.4",
45
+ "acorn": "^8.11.2",
42
46
  "axios": "^1.4.0",
43
47
  "jest": "^29.5.0",
44
48
  "ts-jest": "^29.1.1",
@@ -63,5 +67,5 @@
63
67
  "optional": true
64
68
  }
65
69
  },
66
- "gitHead": "41e3484343d34136e81540d774a101ccf99642b3"
70
+ "gitHead": "0c1330256590bf0b553b2710c3d1e17acbcc099c"
67
71
  }