@hubspot/ui-extensions-dev-server 0.10.2 → 1.0.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.
Files changed (95) hide show
  1. package/README.md +23 -4
  2. package/dist/index.d.ts +3 -3
  3. package/dist/index.js +4 -45
  4. package/dist/lib/DevModeInterface.d.ts +2 -2
  5. package/dist/lib/DevModeInterface.js +12 -28
  6. package/dist/lib/DevModeParentInterface.d.ts +2 -2
  7. package/dist/lib/DevModeParentInterface.js +138 -154
  8. package/dist/lib/DevModeUnifiedInterface.d.ts +2 -2
  9. package/dist/lib/DevModeUnifiedInterface.js +28 -49
  10. package/dist/lib/DevServerState.d.ts +9 -5
  11. package/dist/lib/DevServerState.js +37 -18
  12. package/dist/lib/ExtensionsWebSocket.d.ts +25 -0
  13. package/dist/lib/ExtensionsWebSocket.js +110 -0
  14. package/dist/lib/__mocks__/config.d.ts +2 -0
  15. package/dist/lib/__mocks__/config.js +5 -0
  16. package/dist/lib/__mocks__/isExtensionFile.d.ts +5 -0
  17. package/dist/lib/__mocks__/isExtensionFile.js +11 -0
  18. package/dist/lib/__tests__/DevModeInterface.spec.d.ts +1 -0
  19. package/dist/lib/__tests__/DevModeInterface.spec.js +155 -0
  20. package/dist/lib/__tests__/DevModeParentInterface.spec.d.ts +1 -0
  21. package/dist/lib/__tests__/DevModeParentInterface.spec.js +179 -0
  22. package/dist/lib/__tests__/DevModeUnifiedInterface.spec.d.ts +1 -0
  23. package/dist/lib/__tests__/DevModeUnifiedInterface.spec.js +236 -0
  24. package/dist/lib/__tests__/ExtensionsWebSocket.spec.d.ts +1 -0
  25. package/dist/lib/__tests__/ExtensionsWebSocket.spec.js +304 -0
  26. package/dist/lib/__tests__/ast.spec.d.ts +1 -0
  27. package/dist/lib/__tests__/ast.spec.js +737 -0
  28. package/dist/lib/__tests__/build.spec.d.ts +1 -0
  29. package/dist/lib/__tests__/build.spec.js +159 -0
  30. package/dist/lib/__tests__/config.spec.d.ts +1 -0
  31. package/dist/lib/__tests__/config.spec.js +291 -0
  32. package/dist/lib/__tests__/dev.spec.d.ts +1 -0
  33. package/dist/lib/__tests__/dev.spec.js +80 -0
  34. package/dist/lib/__tests__/extensionsService.spec.d.ts +1 -0
  35. package/dist/lib/__tests__/extensionsService.spec.js +150 -0
  36. package/dist/lib/__tests__/factories.d.ts +48 -0
  37. package/dist/lib/__tests__/factories.js +32 -0
  38. package/dist/lib/__tests__/fixtures/extensionConfig.d.ts +182 -0
  39. package/dist/lib/__tests__/fixtures/extensionConfig.js +304 -0
  40. package/dist/lib/__tests__/fixtures/urls.d.ts +4 -0
  41. package/dist/lib/__tests__/fixtures/urls.js +4 -0
  42. package/dist/lib/__tests__/parsing-utils.spec.d.ts +1 -0
  43. package/dist/lib/__tests__/parsing-utils.spec.js +467 -0
  44. package/dist/lib/__tests__/plugins/codeBlockingPlugin.spec.d.ts +1 -0
  45. package/dist/lib/__tests__/plugins/codeBlockingPlugin.spec.js +112 -0
  46. package/dist/lib/__tests__/plugins/codeCheckingPlugin.spec.d.ts +1 -0
  47. package/dist/lib/__tests__/plugins/codeCheckingPlugin.spec.js +73 -0
  48. package/dist/lib/__tests__/plugins/devBuildPlugin.spec.d.ts +1 -0
  49. package/dist/lib/__tests__/plugins/devBuildPlugin.spec.js +256 -0
  50. package/dist/lib/__tests__/plugins/friendlyLoggingPlugin.spec.d.ts +1 -0
  51. package/dist/lib/__tests__/plugins/friendlyLoggingPlugin.spec.js +65 -0
  52. package/dist/lib/__tests__/plugins/manifestPlugin.spec.d.ts +1 -0
  53. package/dist/lib/__tests__/plugins/manifestPlugin.spec.js +455 -0
  54. package/dist/lib/__tests__/plugins/relevantModulesPlugin.spec.d.ts +1 -0
  55. package/dist/lib/__tests__/plugins/relevantModulesPlugin.spec.js +81 -0
  56. package/dist/lib/__tests__/server.spec.d.ts +1 -0
  57. package/dist/lib/__tests__/server.spec.js +152 -0
  58. package/dist/lib/__tests__/test-utils/ast.d.ts +1 -0
  59. package/dist/lib/__tests__/test-utils/ast.js +4 -0
  60. package/dist/lib/__tests__/utils.spec.d.ts +1 -0
  61. package/dist/lib/__tests__/utils.spec.js +176 -0
  62. package/dist/lib/ast.d.ts +1 -1
  63. package/dist/lib/ast.js +22 -29
  64. package/dist/lib/bin/cli.js +52 -72
  65. package/dist/lib/build.d.ts +1 -1
  66. package/dist/lib/build.js +60 -78
  67. package/dist/lib/config.d.ts +1 -1
  68. package/dist/lib/config.js +31 -34
  69. package/dist/lib/constants.d.ts +0 -2
  70. package/dist/lib/constants.js +20 -27
  71. package/dist/lib/dev.d.ts +1 -1
  72. package/dist/lib/dev.js +52 -69
  73. package/dist/lib/extensionsService.d.ts +1 -1
  74. package/dist/lib/extensionsService.js +21 -15
  75. package/dist/lib/parsing-utils.d.ts +1 -1
  76. package/dist/lib/parsing-utils.js +7 -11
  77. package/dist/lib/plugins/codeBlockingPlugin.d.ts +1 -1
  78. package/dist/lib/plugins/codeBlockingPlugin.js +5 -8
  79. package/dist/lib/plugins/codeCheckingPlugin.d.ts +1 -1
  80. package/dist/lib/plugins/codeCheckingPlugin.js +4 -9
  81. package/dist/lib/plugins/devBuildPlugin.d.ts +2 -2
  82. package/dist/lib/plugins/devBuildPlugin.js +74 -99
  83. package/dist/lib/plugins/friendlyLoggingPlugin.d.ts +2 -2
  84. package/dist/lib/plugins/friendlyLoggingPlugin.js +4 -12
  85. package/dist/lib/plugins/manifestPlugin.d.ts +1 -1
  86. package/dist/lib/plugins/manifestPlugin.js +46 -26
  87. package/dist/lib/plugins/relevantModulesPlugin.d.ts +2 -2
  88. package/dist/lib/plugins/relevantModulesPlugin.js +4 -7
  89. package/dist/lib/server.d.ts +7 -2
  90. package/dist/lib/server.js +85 -84
  91. package/dist/lib/types.d.ts +1 -1
  92. package/dist/lib/types.js +4 -7
  93. package/dist/lib/utils.d.ts +1 -1
  94. package/dist/lib/utils.js +23 -40
  95. package/package.json +44 -31
@@ -1,5 +1,5 @@
1
1
  import { Rollup } from 'vite';
2
- import { Logger, ManifestConfig } from '../types';
2
+ import { Logger, ManifestConfig } from '../types.ts';
3
3
  export interface ManifestPluginOptions {
4
4
  output: string;
5
5
  minify?: boolean;
@@ -1,18 +1,24 @@
1
- "use strict";
2
- /* hs-eslint ignored failing-rules */
3
- /* eslint-disable hubspot-dev/no-unsupported-ts-syntax */
4
- var __importDefault = (this && this.__importDefault) || function (mod) {
5
- return (mod && mod.__esModule) ? mod : { "default": mod };
6
- };
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- const fs_1 = require("fs");
9
- const path_1 = require("path");
10
- const constants_1 = require("../constants");
11
- const path_2 = __importDefault(require("path"));
12
- const utils_1 = require("../utils");
13
- const ast_1 = require("../ast");
1
+ import { readFileSync } from 'fs';
2
+ import { normalize } from 'path';
3
+ import { MANIFEST_FILE } from "../constants.js";
4
+ import path from 'path';
5
+ import { isExtensionFile, isNodeModule } from "../utils.js";
6
+ import { traverseAbstractSyntaxTree } from "../ast.js";
14
7
  const PACKAGE_LOCK_FILE = 'package-lock.json';
15
8
  const PACKAGE_FILE = 'package.json';
9
+ /**
10
+ * Checks if a given filename is a valid module file path. This is necessary because
11
+ * Rollup sometimes passes in a filename that starts with a null byte, which is not a valid
12
+ * module file path. From the Rollup documentation:
13
+ *
14
+ * > If your plugin uses 'virtual modules' (e.g. for helper functions), prefix the module ID with \0.
15
+ * > This prevents other plugins from trying to process it.
16
+ * Source: https://rollupjs.org/plugin-development/#conventions
17
+ *
18
+ * @param filename The filename to check.
19
+ * @returns Whether the filename is a valid module file path.
20
+ */
21
+ const isRealModuleFile = (filename) => typeof filename === 'string' && !filename.startsWith('\0');
16
22
  const manifestPlugin = (options) => {
17
23
  let allDataDependencies;
18
24
  return {
@@ -25,13 +31,14 @@ const manifestPlugin = (options) => {
25
31
  transform(code, filename) {
26
32
  const { logger } = options;
27
33
  // We only need to parse the AST for extension files, so check that first.
28
- const isExtension = (0, utils_1.isExtensionFile)(filename, options.extensionPath || '');
34
+ const isExtension = isRealModuleFile(filename) &&
35
+ isExtensionFile(filename, options.extensionPath || '');
29
36
  if (!isExtension) {
30
37
  return { code, map: null };
31
38
  }
32
39
  try {
33
40
  const ast = this.parse(code);
34
- const sourceCodeMetadata = (0, ast_1.traverseAbstractSyntaxTree)(ast, [], options.extensionPath || process.cwd(), logger);
41
+ const sourceCodeMetadata = traverseAbstractSyntaxTree(ast, [], options.extensionPath || process.cwd(), logger);
35
42
  allDataDependencies = [
36
43
  ...allDataDependencies,
37
44
  ...sourceCodeMetadata.dataDependencies.dependencies,
@@ -46,14 +53,14 @@ const manifestPlugin = (options) => {
46
53
  generateBundle(_rollupOptions, bundle) {
47
54
  const { output, minify = false, extensionPath = process.cwd(), logger, } = options;
48
55
  try {
49
- const filename = path_2.default.parse(output).name;
50
- const manifest = _generateManifestContents(bundle, extensionPath, allDataDependencies, options === null || options === void 0 ? void 0 : options.manifestConfig);
56
+ const filename = path.parse(output).name;
57
+ const manifest = _generateManifestContents(bundle, extensionPath, allDataDependencies, options?.manifestConfig);
51
58
  this.emitFile({
52
59
  type: 'asset',
53
60
  source: minify
54
61
  ? JSON.stringify(manifest)
55
62
  : JSON.stringify(manifest, null, 2),
56
- fileName: (0, path_1.normalize)(`${filename}-${constants_1.MANIFEST_FILE}`),
63
+ fileName: normalize(`${filename}-${MANIFEST_FILE}`),
57
64
  });
58
65
  }
59
66
  catch (e) {
@@ -67,7 +74,7 @@ function _generateManifestContents(bundle, extensionPath, allDataDependencies, a
67
74
  package: _loadPackageFile(extensionPath),
68
75
  };
69
76
  const dataDependencies = {
70
- dataDeps: allDataDependencies !== null && allDataDependencies !== void 0 ? allDataDependencies : [],
77
+ dataDeps: allDataDependencies ?? [],
71
78
  };
72
79
  const variables = {
73
80
  variables: {},
@@ -81,12 +88,25 @@ function _generateManifestContents(bundle, extensionPath, allDataDependencies, a
81
88
  // The keys to bundle are the filename without any path information
82
89
  const bundles = Object.keys(bundle).filter((cur) => cur.endsWith('.js'));
83
90
  if (bundles.length === 1) {
84
- return Object.assign(Object.assign(Object.assign(Object.assign({}, _generateManifestEntry(bundle[bundles[0]], extensionPath)), dataDependencies), baseManifest), variables);
91
+ return {
92
+ ..._generateManifestEntry(bundle[bundles[0]], extensionPath),
93
+ ...dataDependencies,
94
+ ...baseManifest,
95
+ ...variables,
96
+ };
85
97
  }
86
98
  const manifest = bundles.reduce((acc, current) => {
87
- return Object.assign(Object.assign({}, acc), { [current]: _generateManifestEntry(bundle[current], extensionPath) });
99
+ return {
100
+ ...acc,
101
+ [current]: _generateManifestEntry(bundle[current], extensionPath),
102
+ };
88
103
  }, {});
89
- return Object.assign(Object.assign(Object.assign(Object.assign({}, manifest), dataDependencies), baseManifest), variables);
104
+ return {
105
+ ...manifest,
106
+ ...dataDependencies,
107
+ ...baseManifest,
108
+ ...variables,
109
+ };
90
110
  }
91
111
  function _generateManifestEntry(subBundle, extensionPath) {
92
112
  const { facadeModuleId, moduleIds, modules } = subBundle;
@@ -97,7 +117,7 @@ function _generateManifestEntry(subBundle, extensionPath) {
97
117
  }
98
118
  function _loadJsonFileSafely(extensionPath, filename) {
99
119
  try {
100
- return JSON.parse((0, fs_1.readFileSync)(path_2.default.join(extensionPath, filename)).toString());
120
+ return JSON.parse(readFileSync(path.join(extensionPath, filename)).toString());
101
121
  }
102
122
  catch (e) {
103
123
  return undefined;
@@ -113,7 +133,7 @@ function _stripPathPriorToExtDir(filepath, extensionPath) {
113
133
  extensionPath = extensionPath.endsWith('/')
114
134
  ? extensionPath
115
135
  : `${extensionPath}/`;
116
- return filepath === null || filepath === void 0 ? void 0 : filepath.split(extensionPath).pop();
136
+ return filepath?.split(extensionPath).pop();
117
137
  }
118
138
  function _buildModulesInfo(moduleIds, modules, extensionPath) {
119
139
  const accumulator = {
@@ -126,7 +146,7 @@ function _buildModulesInfo(moduleIds, modules, extensionPath) {
126
146
  module: _stripPathPriorToExtDir(mod, extensionPath),
127
147
  renderedExports,
128
148
  };
129
- if ((0, utils_1.isNodeModule)(moduleData.module)) {
149
+ if (isNodeModule(moduleData.module)) {
130
150
  acc.external.push(moduleData);
131
151
  }
132
152
  else {
@@ -135,4 +155,4 @@ function _buildModulesInfo(moduleIds, modules, extensionPath) {
135
155
  return acc;
136
156
  }, accumulator);
137
157
  }
138
- exports.default = manifestPlugin;
158
+ export default manifestPlugin;
@@ -1,5 +1,5 @@
1
- import Vite from 'vite';
2
- import { Logger } from '../types';
1
+ import * as Vite from 'vite';
2
+ import { Logger } from '../types.ts';
3
3
  export interface RelevantModules {
4
4
  [key: string]: string[];
5
5
  }
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getRelevantModules = getRelevantModules;
4
- const utils_1 = require("../utils");
1
+ import { isNodeModule } from "../utils.js";
5
2
  const relevantModules = {};
6
- function getRelevantModules(output) {
3
+ export function getRelevantModules(output) {
7
4
  return relevantModules[output] || [];
8
5
  }
9
6
  const relevantModulesPlugin = ({ output, logger }) => {
@@ -16,7 +13,7 @@ const relevantModulesPlugin = ({ output, logger }) => {
16
13
  logger.error('Invalid bundle format, please try saving the extension again. If the problem persists try restarting `hs project dev`');
17
14
  return;
18
15
  }
19
- const updatedRelevantModules = subBundle.moduleIds.filter((moduleId) => !(0, utils_1.isNodeModule)(moduleId));
16
+ const updatedRelevantModules = subBundle.moduleIds.filter((moduleId) => !isNodeModule(moduleId));
20
17
  if (updatedRelevantModules.length === 0) {
21
18
  logger.error('Unable to determine relevant files to watch, please try saving the extension again. If the problem persists try restarting `hs project dev`');
22
19
  return;
@@ -25,4 +22,4 @@ const relevantModulesPlugin = ({ output, logger }) => {
25
22
  },
26
23
  };
27
24
  };
28
- exports.default = relevantModulesPlugin;
25
+ export default relevantModulesPlugin;
@@ -1,8 +1,13 @@
1
+ import { Server } from 'http';
1
2
  import { ViteDevServer } from 'vite';
2
- import { DevServerState } from './DevServerState';
3
+ import { DevServerState } from './DevServerState.ts';
3
4
  interface StartDevServerArgs {
4
5
  devServerState: DevServerState;
5
6
  viteDevServer: ViteDevServer;
6
7
  }
7
- declare function startDevServer({ devServerState, viteDevServer, }: StartDevServerArgs): Promise<() => Promise<void>>;
8
+ interface StartDevServerReturn {
9
+ httpServer: Server;
10
+ shutdown: () => Promise<void>;
11
+ }
12
+ declare function startDevServer({ devServerState, viteDevServer, }: StartDevServerArgs): Promise<StartDevServerReturn>;
8
13
  export default startDevServer;
@@ -1,25 +1,10 @@
1
- "use strict";
2
- /* eslint-disable hubspot-dev/no-unsupported-ts-syntax */
3
- /* eslint-disable no-unused-expressions */
4
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
- return new (P || (P = Promise))(function (resolve, reject) {
7
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
10
- step((generator = generator.apply(thisArg, _arguments || [])).next());
11
- });
12
- };
13
- var __importDefault = (this && this.__importDefault) || function (mod) {
14
- return (mod && mod.__esModule) ? mod : { "default": mod };
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- const express_1 = __importDefault(require("express"));
18
- const cors_1 = __importDefault(require("cors"));
19
- const constants_1 = require("./constants");
20
- const extensionsService_1 = __importDefault(require("./extensionsService"));
21
- const app_functions_dev_server_1 = require("@hubspot/app-functions-dev-server");
22
- const utils_1 = require("./utils");
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import { PROXY_CAPABILITY, SERVER_CAPABILITIES } from "./constants.js";
4
+ import extensionsService from "./extensionsService.js";
5
+ import { AppFunctionExecutionService, AppProxyService, } from '@hubspot/app-functions-dev-server';
6
+ import { extractAllowedUrls } from "./utils.js";
7
+ import { ExtensionsWebSocket } from "./ExtensionsWebSocket.js";
23
8
  function listen(app, port) {
24
9
  return new Promise((resolve, reject) => {
25
10
  const server = app
@@ -31,68 +16,84 @@ function listen(app, port) {
31
16
  });
32
17
  });
33
18
  }
34
- function startDevServer(_a) {
35
- return __awaiter(this, arguments, void 0, function* ({ devServerState, viteDevServer, }) {
36
- var _b;
37
- const app = (0, express_1.default)();
38
- // Setup middleware
39
- app.use((0, cors_1.default)());
40
- app.use(express_1.default.static(devServerState.outputDir));
41
- const capabilities = [...constants_1.SERVER_CAPABILITIES];
42
- const middlewares = [];
43
- if (!devServerState.isPublicApp()) {
44
- middlewares.push((0, app_functions_dev_server_1.AppFunctionExecutionService)(Object.assign(Object.assign({}, devServerState.functionsConfig), { logger: devServerState.logger })));
45
- devServerState.logger.info(`Serving app functions locally (platform version ${devServerState.functionsConfig.platformVersion})`);
46
- }
47
- if (devServerState.localDevUrlMapping &&
48
- Object.keys(devServerState.localDevUrlMapping).length > 0) {
49
- devServerState.logger.info('Proxy config discovered, enabling local proxy mode');
50
- middlewares.push((0, app_functions_dev_server_1.AppProxyService)({
51
- localDevUrlMapping: devServerState.localDevUrlMapping,
52
- logger: devServerState.logger,
53
- accountId: devServerState.functionsConfig.accountId,
54
- allowedUrls: (0, utils_1.extractAllowedUrls)(devServerState.appConfig),
55
- }));
56
- capabilities.push(constants_1.PROXY_CAPABILITY);
57
- }
58
- if (middlewares.length > 0) {
59
- app.use('/api/crm-extensibility/execution/internal/v3', ...middlewares);
60
- }
61
- const endpointsAdded = extensionsService_1.default.add(app, devServerState, capabilities);
62
- const { expressPort } = devServerState;
63
- endpointsAdded.forEach((endpoint) => {
64
- devServerState.logger.debug(`Listening at http://hslocal.net:${expressPort}${endpoint}`);
65
- });
66
- // Vite middlewares needs to go last because it's greedy and will block other middleware
67
- app.use(viteDevServer.middlewares);
68
- let server;
69
- try {
70
- server = yield listen(app, devServerState.expressPort);
71
- }
72
- catch (e) {
73
- if (e.code === 'EADDRINUSE') {
74
- throw new Error(`Port ${devServerState.expressPort} is already in use.`);
75
- }
76
- throw new Error(e);
19
+ async function startDevServer({ devServerState, viteDevServer, }) {
20
+ const app = express();
21
+ // Setup middleware
22
+ app.use(cors());
23
+ app.use(express.static(devServerState.outputDir));
24
+ const capabilities = [...SERVER_CAPABILITIES];
25
+ const middlewares = [];
26
+ if (!devServerState.isPublicApp()) {
27
+ middlewares.push(AppFunctionExecutionService({
28
+ ...devServerState.functionsConfig,
29
+ logger: devServerState.logger,
30
+ }));
31
+ devServerState.logger.info(`Serving app functions locally (platform version ${devServerState.functionsConfig.platformVersion})`);
32
+ }
33
+ if (devServerState.localDevUrlMapping &&
34
+ Object.keys(devServerState.localDevUrlMapping).length > 0) {
35
+ devServerState.logger.info('Proxy config discovered, enabling local proxy mode');
36
+ middlewares.push(AppProxyService({
37
+ localDevUrlMapping: devServerState.localDevUrlMapping,
38
+ logger: devServerState.logger,
39
+ accountId: devServerState.functionsConfig.accountId,
40
+ allowedUrls: extractAllowedUrls(devServerState.appConfig),
41
+ }));
42
+ capabilities.push(PROXY_CAPABILITY);
43
+ }
44
+ if (middlewares.length > 0) {
45
+ app.use('/api/crm-extensibility/execution/internal/v3', ...middlewares);
46
+ }
47
+ const endpointsAdded = extensionsService.add(app, devServerState, capabilities);
48
+ const { expressPort } = devServerState;
49
+ endpointsAdded.forEach((endpoint) => {
50
+ devServerState.logger.debug(`Listening at http://hslocal.net:${expressPort}${endpoint}`);
51
+ });
52
+ // Vite middlewares needs to go last because it's greedy and will block other middleware
53
+ app.use(viteDevServer.middlewares);
54
+ let server;
55
+ try {
56
+ server = await listen(app, devServerState.expressPort);
57
+ }
58
+ catch (e) {
59
+ if (e.code === 'EADDRINUSE') {
60
+ throw new Error(`Port ${devServerState.expressPort} is already in use.`);
77
61
  }
78
- (_b = devServerState.extensionsMetadata) === null || _b === void 0 ? void 0 : _b.forEach((metadata) => {
79
- const { baseMessage } = metadata;
80
- devServerState.logger.debug(`Listening at ${baseMessage.callback}`);
81
- });
82
- return function shutdown() {
83
- return __awaiter(this, void 0, void 0, function* () {
84
- try {
85
- yield viteDevServer.pluginContainer.close();
86
- // Stop new connections to express server
87
- server.close(() => { });
88
- yield viteDevServer.close();
89
- }
90
- catch (e) {
91
- devServerState.logger.debug(`Error shutting down ${e}`);
92
- }
93
- devServerState.logger.info('Extension dev server done cleaning up');
94
- });
95
- };
62
+ throw new Error(e);
63
+ }
64
+ /**
65
+ * We use a custom WebSocket server instead of Vite's built-in one because:
66
+ * 1. We send HubSpot-specific extension metadata (not standard HMR messages)
67
+ * 2. We need cross-origin connections from HubSpot iframes
68
+ * 3. Our message format { event: 'start', ...metadata } doesn't match Vite's protocol
69
+ */
70
+ const wss = new ExtensionsWebSocket(server, devServerState);
71
+ devServerState.extensionsWebSocket = wss;
72
+ // Trigger the WebSocket setup that was deferred from the plugin's configureServer hook
73
+ // This must happen after the WebSocket is initialized to avoid race conditions
74
+ devServerState.triggerWebSocketSetup();
75
+ devServerState.extensionsMetadata?.forEach((metadata) => {
76
+ const { baseMessage } = metadata;
77
+ devServerState.logger.debug(`Listening at ${baseMessage.callback}`);
96
78
  });
79
+ return {
80
+ httpServer: server,
81
+ shutdown: async function shutdown() {
82
+ try {
83
+ await viteDevServer.pluginContainer.close();
84
+ // Close WebSocket server first to reject new connections
85
+ await devServerState.getExtensionsWebSocket().close();
86
+ // Close HTTP server
87
+ await new Promise((resolve) => {
88
+ server.close(() => resolve());
89
+ });
90
+ await viteDevServer.close();
91
+ }
92
+ catch (e) {
93
+ devServerState.logger.debug(`Error shutting down ${e}`);
94
+ }
95
+ devServerState.logger.info('Extension dev server done cleaning up');
96
+ },
97
+ };
97
98
  }
98
- exports.default = startDevServer;
99
+ export default startDevServer;
@@ -1,4 +1,4 @@
1
- import { PLATFORM_VERSION, PRIVATE_APP, PUBLIC_APP } from './constants';
1
+ import { PLATFORM_VERSION, PRIVATE_APP, PUBLIC_APP } from './constants.ts';
2
2
  import { LocalDevUrlMapping } from '@hubspot/app-functions-dev-server';
3
3
  export interface ObjectTypes {
4
4
  name: string;
package/dist/lib/types.js CHANGED
@@ -1,15 +1,12 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UnifiedComponentTypes = exports.UnifiedAppAuthTypes = void 0;
4
- var UnifiedAppAuthTypes;
1
+ export var UnifiedAppAuthTypes;
5
2
  (function (UnifiedAppAuthTypes) {
6
3
  UnifiedAppAuthTypes["OAUTH"] = "OAUTH";
7
4
  UnifiedAppAuthTypes["STATIC"] = "STATIC";
8
- })(UnifiedAppAuthTypes || (exports.UnifiedAppAuthTypes = UnifiedAppAuthTypes = {}));
9
- var UnifiedComponentTypes;
5
+ })(UnifiedAppAuthTypes || (UnifiedAppAuthTypes = {}));
6
+ export var UnifiedComponentTypes;
10
7
  (function (UnifiedComponentTypes) {
11
8
  UnifiedComponentTypes["CARD"] = "CARD";
12
9
  UnifiedComponentTypes["APPLICATION"] = "APPLICATION";
13
10
  UnifiedComponentTypes["SETTINGS"] = "SETTINGS";
14
11
  UnifiedComponentTypes["PAGE"] = "PAGE";
15
- })(UnifiedComponentTypes || (exports.UnifiedComponentTypes = UnifiedComponentTypes = {}));
12
+ })(UnifiedComponentTypes || (UnifiedComponentTypes = {}));
@@ -1,4 +1,4 @@
1
- import { AppConfig, ExtensionConfig } from './types';
1
+ import { AppConfig, ExtensionConfig } from './types.ts';
2
2
  export declare function getUrlSafeFileName(filePath: string): string;
3
3
  export declare function stripAnsiColorCodes(stringWithColorCodes: string | undefined | null): string | null;
4
4
  export declare function loadManifest(outputDir: string, output: string): any;
package/dist/lib/utils.js CHANGED
@@ -1,28 +1,12 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.UnhandledPlatformVersionError = void 0;
7
- exports.getUrlSafeFileName = getUrlSafeFileName;
8
- exports.stripAnsiColorCodes = stripAnsiColorCodes;
9
- exports.loadManifest = loadManifest;
10
- exports.buildSourceId = buildSourceId;
11
- exports.isNodeModule = isNodeModule;
12
- exports.isExtensionFile = isExtensionFile;
13
- exports.throwUnhandledPlatformVersionError = throwUnhandledPlatformVersionError;
14
- exports.extractAllowedUrls = extractAllowedUrls;
15
- exports.generateHash = generateHash;
16
- exports.isImage = isImage;
17
- const path_1 = __importDefault(require("path"));
18
- const fs_1 = __importDefault(require("fs"));
19
- const constants_1 = require("./constants");
20
- function getUrlSafeFileName(filePath) {
21
- const { name } = path_1.default.parse(filePath);
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { MANIFEST_FILE } from "./constants.js";
4
+ export function getUrlSafeFileName(filePath) {
5
+ const { name } = path.parse(filePath);
22
6
  return encodeURIComponent(`${name}.js`);
23
7
  }
24
8
  // Strips ANSI color codes out of strings because we don't want to pass them to the browser
25
- function stripAnsiColorCodes(stringWithColorCodes) {
9
+ export function stripAnsiColorCodes(stringWithColorCodes) {
26
10
  if (!stringWithColorCodes) {
27
11
  return null;
28
12
  }
@@ -30,58 +14,57 @@ function stripAnsiColorCodes(stringWithColorCodes) {
30
14
  // eslint-disable-next-line no-control-regex
31
15
  /[\u001b][[]*([0-9]{1,4};?)*[m]/g, '');
32
16
  }
33
- function loadManifest(outputDir, output) {
17
+ export function loadManifest(outputDir, output) {
34
18
  try {
35
- return JSON.parse(fs_1.default
36
- .readFileSync(path_1.default.join(outputDir, `${output}-${constants_1.MANIFEST_FILE}`))
19
+ return JSON.parse(fs
20
+ .readFileSync(path.join(outputDir, `${output}-${MANIFEST_FILE}`))
37
21
  .toString());
38
22
  }
39
23
  catch (e) {
40
24
  return {};
41
25
  }
42
26
  }
43
- function buildSourceId(appConfig, extensionConfig) {
27
+ export function buildSourceId(appConfig, extensionConfig) {
44
28
  if (appConfig.uid && extensionConfig.data.uid) {
45
29
  return `${appConfig.uid}::${extensionConfig.data.uid}`;
46
30
  }
47
31
  return null;
48
32
  }
49
- function isNodeModule(filepath) {
33
+ export function isNodeModule(filepath) {
50
34
  if (!filepath) {
51
35
  return false;
52
36
  }
53
- const directory = path_1.default.parse(filepath).dir;
37
+ const directory = path.parse(filepath).dir;
54
38
  return directory.includes('node_modules');
55
39
  }
56
40
  /**
57
41
  * Check if a given file is within the extension path
58
42
  */
59
- function isExtensionFile(filepath, extensionPath) {
43
+ export function isExtensionFile(filepath, extensionPath) {
60
44
  if (!filepath) {
61
45
  return false;
62
46
  }
63
47
  try {
64
- const absoluteFilePath = fs_1.default.realpathSync(filepath);
65
- const absoluteExtensionDirPath = fs_1.default.realpathSync(extensionPath);
66
- const relativePath = path_1.default.relative(absoluteExtensionDirPath, absoluteFilePath);
67
- return !relativePath.startsWith('..') && !path_1.default.isAbsolute(relativePath);
48
+ const absoluteFilePath = fs.realpathSync(filepath);
49
+ const absoluteExtensionDirPath = fs.realpathSync(extensionPath);
50
+ const relativePath = path.relative(absoluteExtensionDirPath, absoluteFilePath);
51
+ return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
68
52
  }
69
53
  catch (e) {
70
- // console.log(`Error checking if ${filepath} is in extension path: ${e}`);
54
+ console.log(`Error checking if ${filepath} is in extension path: ${e}`);
71
55
  // If there's an error, we can't determine if the file is in the extension path, so return false.
72
56
  return false;
73
57
  }
74
58
  }
75
- class UnhandledPlatformVersionError extends Error {
59
+ export class UnhandledPlatformVersionError extends Error {
76
60
  constructor(platformVersion) {
77
61
  super(`Unsupported platform version "${platformVersion}"`);
78
62
  }
79
63
  }
80
- exports.UnhandledPlatformVersionError = UnhandledPlatformVersionError;
81
- function throwUnhandledPlatformVersionError(platformVersion) {
64
+ export function throwUnhandledPlatformVersionError(platformVersion) {
82
65
  throw new UnhandledPlatformVersionError(platformVersion);
83
66
  }
84
- function extractAllowedUrls(appConfig) {
67
+ export function extractAllowedUrls(appConfig) {
85
68
  if (!appConfig || !('allowedUrls' in appConfig) || !appConfig.allowedUrls) {
86
69
  return [];
87
70
  }
@@ -100,7 +83,7 @@ function simpleHash(input) {
100
83
  * Arrays and objects are stringified to ensure it works for all types.
101
84
  * Uses the same simple hash algorithm as the browser version for consistency.
102
85
  */
103
- function generateHash(...args) {
86
+ export function generateHash(...args) {
104
87
  try {
105
88
  // First make sure all the values are strings
106
89
  const normalizedArgs = args.map((arg) => {
@@ -125,6 +108,6 @@ function generateHash(...args) {
125
108
  /**
126
109
  * Check if a given URL is an image (of a type we support)
127
110
  */
128
- function isImage(url) {
111
+ export function isImage(url) {
129
112
  return /\.(png|jpg|jpeg|gif|svg|webp|avif|raw|url|inline)$/.test(url);
130
113
  }