@hubspot/ui-extensions-dev-server 0.9.5 → 0.10.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.
@@ -1,7 +1,7 @@
1
- import { AppExtensionMapping, UnifiedProjectComponentMap, UnifiedDevModeSetupArguments } from './types';
1
+ import { AppExtensionMapping, UnifiedProjectComponentMap, UnifiedDevModeSetupArguments, ProfileVariables } from './types';
2
2
  import { DevModeParentInterface } from './DevModeParentInterface';
3
3
  declare class DevModeUnifiedInterface extends DevModeParentInterface {
4
- _generateAppExtensionMappings(components: UnifiedProjectComponentMap): AppExtensionMapping[];
4
+ _generateAppExtensionMappings(components: UnifiedProjectComponentMap, profileData?: ProfileVariables): AppExtensionMapping[];
5
5
  setup(args: UnifiedDevModeSetupArguments): Promise<void>;
6
6
  }
7
7
  export { DevModeUnifiedInterface as DevModeUnifiedInterfaceNonSingleton };
@@ -20,8 +20,16 @@ const constants_1 = require("./constants");
20
20
  const types_1 = require("./types");
21
21
  const DevModeParentInterface_1 = require("./DevModeParentInterface");
22
22
  const utils_1 = require("./utils");
23
+ function getComponentName(componentType) {
24
+ if (componentType === types_1.UnifiedComponentTypes.SETTINGS) {
25
+ return 'Settings';
26
+ }
27
+ if (componentType === types_1.UnifiedComponentTypes.PAGE) {
28
+ return 'App Home';
29
+ }
30
+ }
23
31
  class DevModeUnifiedInterface extends DevModeParentInterface_1.DevModeParentInterface {
24
- _generateAppExtensionMappings(components) {
32
+ _generateAppExtensionMappings(components, profileData) {
25
33
  var _a, _b, _c, _d;
26
34
  const mappings = [];
27
35
  // Loop over all of the components that are passed in
@@ -55,6 +63,7 @@ class DevModeUnifiedInterface extends DevModeParentInterface_1.DevModeParentInte
55
63
  allowedUrls: ((_d = appData.config) === null || _d === void 0 ? void 0 : _d.permittedUrls)
56
64
  ? Object.values(appData.config.permittedUrls).flat()
57
65
  : [],
66
+ variables: profileData || {},
58
67
  };
59
68
  // Then get all the supported extensions
60
69
  const extensionUids = allComponentUids.filter((componentUid) => {
@@ -62,12 +71,14 @@ class DevModeUnifiedInterface extends DevModeParentInterface_1.DevModeParentInte
62
71
  });
63
72
  // Build the extension mapping data
64
73
  extensionUids.forEach((extensionUid) => {
74
+ var _a;
65
75
  const extension = components[extensionUid];
66
76
  // Update the extension entrypoint to be "relative" to the extension directory (eg from /app/card/card.jsx to ./card.jsx)
67
77
  extension.config.entrypoint = `./${path_1.default.basename(extension.config.entrypoint)}`;
68
78
  // Hardcode the extension name if this is a settings extension (the user does not provide a name for their settings card).
69
- if (extension.componentType === types_1.UnifiedComponentTypes.SETTINGS) {
70
- extension.config.name = 'Settings';
79
+ if (extension.componentType === types_1.UnifiedComponentTypes.SETTINGS ||
80
+ extension.componentType === types_1.UnifiedComponentTypes.PAGE) {
81
+ extension.config.name = (_a = getComponentName(extension.componentType)) !== null && _a !== void 0 ? _a : '';
71
82
  }
72
83
  // Add them to the app config
73
84
  switch (extension.componentType) {
@@ -117,8 +128,9 @@ class DevModeUnifiedInterface extends DevModeParentInterface_1.DevModeParentInte
117
128
  return mappings;
118
129
  }
119
130
  setup(args) {
131
+ var _a;
120
132
  return __awaiter(this, void 0, void 0, function* () {
121
- args.choices = this._generateAppExtensionMappings(args.components);
133
+ args.choices = this._generateAppExtensionMappings(args.components, (_a = args.profileData) !== null && _a !== void 0 ? _a : {});
122
134
  yield this.parentSetup(args);
123
135
  });
124
136
  }
@@ -46,6 +46,7 @@ const buildSteps = {
46
46
  },
47
47
  };
48
48
  program
49
+ .option('-v, --profile-variables <path>', 'path to a json file with profile variables')
49
50
  .command('build <module>', { isDefault: true })
50
51
  .description('Build extension source code.')
51
52
  .action((module) => __awaiter(void 0, void 0, void 0, function* () {
@@ -74,8 +75,15 @@ function runCommand(command, options) {
74
75
  });
75
76
  }
76
77
  // Mirrors: https://git.hubteam.com/HubSpot/Artifactor/blob/f5cbea91d7a7dfb6278e878ae583e69022384fb5/ArtifactorFunctions/functions/node_18x/uie-remote-build/index.js#L59-L63
77
- function build({ extensionRoot, extensionDist, entrypoint }) {
78
- return (0, build_1.remoteBuild)(extensionRoot, entrypoint, extensionDist);
78
+ function build({ extensionRoot, extensionDist, entrypoint, profileVariables, }) {
79
+ return (0, build_1.remoteBuild)({
80
+ root: extensionRoot,
81
+ entryPoint: entrypoint,
82
+ outputDir: extensionDist,
83
+ appConfig: {
84
+ variables: profileVariables,
85
+ },
86
+ });
79
87
  }
80
88
  // Mirrors: https://git.hubteam.com/HubSpot/Artifactor/blob/f5cbea91d7a7dfb6278e878ae583e69022384fb5/ArtifactorFunctions/functions/node_18x/uie-remote-build/index.js#L53-L57
81
89
  function installDeps(options) {
@@ -103,11 +111,26 @@ function getOptions(modulePath) {
103
111
  const extensionRoot = node_path_1.default.dirname(entrypoint);
104
112
  const extensionDist = node_path_1.default.join(extensionRoot, 'dist');
105
113
  const spinner = (0, ora_1.default)();
114
+ // The Artifactor changes related to this are not yet available.
115
+ // When it is, this will mirror the process where if applicable, a profile-variables.json file is available in the build bundle.
116
+ const programOptions = program.opts();
117
+ let profileVariables = {};
118
+ if (programOptions.profileVariables) {
119
+ const profileVariablePath = programOptions.profileVariables;
120
+ const profileVariableFullPath = node_path_1.default.isAbsolute(profileVariablePath)
121
+ ? profileVariablePath
122
+ : node_path_1.default.resolve(process.cwd(), profileVariablePath);
123
+ if (node_fs_1.default.existsSync(profileVariableFullPath) &&
124
+ node_path_1.default.extname(profileVariableFullPath) === '.json') {
125
+ profileVariables = JSON.parse(node_fs_1.default.readFileSync(profileVariableFullPath, 'utf-8'));
126
+ }
127
+ }
106
128
  return {
107
129
  extensionRoot,
108
130
  extensionDist,
109
131
  entrypoint,
110
132
  spinner,
133
+ profileVariables,
111
134
  };
112
135
  }
113
136
  function execAsync(command, options) {
@@ -1,4 +1,5 @@
1
1
  import { InlineConfig } from 'vite';
2
+ import { ManifestConfig } from './types';
2
3
  interface BuildSingleExtensionArgs {
3
4
  file: string;
4
5
  outputDir?: string;
@@ -6,9 +7,17 @@ interface BuildSingleExtensionArgs {
6
7
  minify?: boolean;
7
8
  root?: string;
8
9
  logLevel?: InlineConfig['logLevel'];
10
+ appConfig?: ManifestConfig;
11
+ }
12
+ interface RemoteBuildArgs {
13
+ root: string;
14
+ entryPoint: string;
15
+ outputDir?: string;
16
+ logLevel?: BuildSingleExtensionArgs['logLevel'];
17
+ appConfig?: ManifestConfig;
9
18
  }
10
19
  export declare const extensionErrorBaseMessage: string;
11
20
  export declare function buildSingleExtension({ file, outputDir, emptyOutDir, minify, root, // This is the vite default, so using that as our default
12
- logLevel, }: BuildSingleExtensionArgs): Promise<void>;
13
- export declare function remoteBuild(root: string, entryPoint: string, outputDir?: string, logLevel?: BuildSingleExtensionArgs['logLevel']): Promise<void>;
21
+ logLevel, appConfig, }: BuildSingleExtensionArgs): Promise<void>;
22
+ export declare function remoteBuild(args: RemoteBuildArgs): Promise<void>;
14
23
  export {};
package/dist/lib/build.js CHANGED
@@ -23,7 +23,7 @@ const friendlyLoggingPlugin_1 = __importDefault(require("./plugins/friendlyLoggi
23
23
  const allowedExtensions = ['.js', '.ts', '.tsx', '.jsx'];
24
24
  exports.extensionErrorBaseMessage = `Supported file extensions are [${allowedExtensions.join(', ')}], received:`;
25
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
26
- logLevel = 'info', }) {
26
+ logLevel = 'info', appConfig, }) {
27
27
  return __awaiter(this, void 0, void 0, function* () {
28
28
  const output = (0, utils_1.getUrlSafeFileName)(file);
29
29
  yield (0, vite_1.build)({
@@ -40,7 +40,12 @@ logLevel = 'info', }) {
40
40
  fileName: () => output,
41
41
  },
42
42
  rollupOptions: Object.assign(Object.assign({}, constants_1.ROLLUP_OPTIONS), { plugins: [
43
- (0, manifestPlugin_1.default)({ output, extensionPath: root, logger: console }),
43
+ (0, manifestPlugin_1.default)({
44
+ output,
45
+ extensionPath: root,
46
+ logger: console,
47
+ manifestConfig: appConfig,
48
+ }),
44
49
  (0, friendlyLoggingPlugin_1.default)({ logger: console }),
45
50
  (0, codeBlockingPlugin_1.default)({ logger: console, extensionPath: root }),
46
51
  ] }),
@@ -52,8 +57,17 @@ logLevel = 'info', }) {
52
57
  });
53
58
  }
54
59
  exports.buildSingleExtension = buildSingleExtension;
55
- function remoteBuild(root, entryPoint, outputDir = constants_1.OUTPUT_DIR, logLevel) {
60
+ function remoteBuild(args) {
56
61
  return __awaiter(this, void 0, void 0, function* () {
62
+ const { root, entryPoint, outputDir = constants_1.OUTPUT_DIR, logLevel, appConfig, } = args;
63
+ if (!root) {
64
+ console.error('remoteBuild Error: root is required');
65
+ return;
66
+ }
67
+ if (!entryPoint) {
68
+ console.error('remoteBuild Error: entryPoint is required');
69
+ return;
70
+ }
57
71
  const fileInfo = path_1.default.parse(entryPoint);
58
72
  if (!allowedExtensions.includes(fileInfo.ext)) {
59
73
  throw new Error(`${exports.extensionErrorBaseMessage} ${fileInfo.ext}`);
@@ -64,6 +78,7 @@ function remoteBuild(root, entryPoint, outputDir = constants_1.OUTPUT_DIR, logLe
64
78
  minify: true,
65
79
  root,
66
80
  logLevel,
81
+ appConfig,
67
82
  });
68
83
  });
69
84
  }
@@ -29,5 +29,6 @@ export declare const PUBLIC_APP = "public-app";
29
29
  export declare const PRIVATE_APP = "private-app";
30
30
  export declare const CARD_EXTENSION = "CARD";
31
31
  export declare const SETTINGS_EXTENSION = "SETTINGS";
32
+ export declare const PAGE_EXTENSION = "PAGE";
32
33
  export declare const SUPPORTED_APP_TYPES: string[];
33
34
  export declare const SUPPORTED_EXTENSION_TYPES: string[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SUPPORTED_EXTENSION_TYPES = exports.SUPPORTED_APP_TYPES = exports.SETTINGS_EXTENSION = exports.CARD_EXTENSION = exports.PRIVATE_APP = exports.PUBLIC_APP = exports.PLATFORM_VERSION = exports.SERVER_CAPABILITIES = exports.PROXY_CAPABILITY = 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.OUTPUT_DIR = void 0;
3
+ exports.SUPPORTED_EXTENSION_TYPES = exports.SUPPORTED_APP_TYPES = exports.PAGE_EXTENSION = exports.SETTINGS_EXTENSION = exports.CARD_EXTENSION = exports.PRIVATE_APP = exports.PUBLIC_APP = exports.PLATFORM_VERSION = exports.SERVER_CAPABILITIES = exports.PROXY_CAPABILITY = 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.OUTPUT_DIR = void 0;
4
4
  exports.OUTPUT_DIR = 'dist';
5
5
  exports.MANIFEST_FILE = 'manifest.json';
6
6
  exports.EXPRESS_SERVER_ID = 'ui-extensions-dev-server';
@@ -41,5 +41,10 @@ exports.PUBLIC_APP = 'public-app';
41
41
  exports.PRIVATE_APP = 'private-app';
42
42
  exports.CARD_EXTENSION = 'CARD';
43
43
  exports.SETTINGS_EXTENSION = 'SETTINGS';
44
+ exports.PAGE_EXTENSION = 'PAGE';
44
45
  exports.SUPPORTED_APP_TYPES = [exports.PUBLIC_APP, exports.PRIVATE_APP];
45
- exports.SUPPORTED_EXTENSION_TYPES = [exports.CARD_EXTENSION, exports.SETTINGS_EXTENSION];
46
+ exports.SUPPORTED_EXTENSION_TYPES = [
47
+ exports.CARD_EXTENSION,
48
+ exports.SETTINGS_EXTENSION,
49
+ exports.PAGE_EXTENSION,
50
+ ];
@@ -49,6 +49,14 @@ const codeBlockingPlugin_1 = __importDefault(require("./codeBlockingPlugin"));
49
49
  function addVersionToBaseMessage(baseMessage) {
50
50
  return Object.assign(Object.assign({}, baseMessage), { version: constants_1.WEBSOCKET_MESSAGE_VERSION });
51
51
  }
52
+ function isValidVariablesRecord(obj) {
53
+ if (!obj || typeof obj !== 'object')
54
+ return false;
55
+ return Object.entries(obj).every(([key, value]) => typeof key === 'string' &&
56
+ (typeof value === 'string' ||
57
+ typeof value === 'number' ||
58
+ typeof value === 'boolean'));
59
+ }
52
60
  const devBuildPlugin = (options) => {
53
61
  const { devServerState } = options;
54
62
  const { logger } = devServerState;
@@ -72,6 +80,14 @@ const devBuildPlugin = (options) => {
72
80
  try {
73
81
  const { config: extensionConfig } = extensionMetadata;
74
82
  const { extensionPath } = extensionConfig;
83
+ let manifestConfig = {};
84
+ if (devServerState.appConfig &&
85
+ 'variables' in devServerState.appConfig &&
86
+ isValidVariablesRecord(devServerState.appConfig.variables)) {
87
+ manifestConfig = {
88
+ variables: devServerState.appConfig.variables,
89
+ };
90
+ }
75
91
  yield (0, vite_1.build)({
76
92
  logLevel: 'warn',
77
93
  mode: 'development',
@@ -98,6 +114,7 @@ const devBuildPlugin = (options) => {
98
114
  output: extensionConfig.output,
99
115
  extensionPath,
100
116
  logger,
117
+ manifestConfig,
101
118
  }),
102
119
  (0, codeCheckingPlugin_1.default)({
103
120
  output: path_1.default.join(devServerState.outputDir, extensionConfig.output),
@@ -1,10 +1,11 @@
1
1
  import { Rollup } from 'vite';
2
- import { Logger } from '../types';
2
+ import { Logger, ManifestConfig } from '../types';
3
3
  export interface ManifestPluginOptions {
4
4
  output: string;
5
5
  minify?: boolean;
6
6
  extensionPath?: string;
7
7
  logger: Logger;
8
+ manifestConfig?: ManifestConfig;
8
9
  }
9
10
  export type ManifestPlugin = (options: ManifestPluginOptions) => Rollup.Plugin;
10
11
  declare const manifestPlugin: ManifestPlugin;
@@ -47,7 +47,7 @@ const manifestPlugin = (options) => {
47
47
  const { output, minify = false, extensionPath = process.cwd(), logger, } = options;
48
48
  try {
49
49
  const filename = path_2.default.parse(output).name;
50
- const manifest = _generateManifestContents(bundle, extensionPath, allDataDependencies);
50
+ const manifest = _generateManifestContents(bundle, extensionPath, allDataDependencies, options === null || options === void 0 ? void 0 : options.manifestConfig);
51
51
  this.emitFile({
52
52
  type: 'asset',
53
53
  source: minify
@@ -62,22 +62,31 @@ const manifestPlugin = (options) => {
62
62
  },
63
63
  };
64
64
  };
65
- function _generateManifestContents(bundle, extensionPath, allDataDependencies) {
65
+ function _generateManifestContents(bundle, extensionPath, allDataDependencies, appConfig) {
66
66
  const baseManifest = {
67
67
  package: _loadPackageFile(extensionPath),
68
68
  };
69
69
  const dataDependencies = {
70
70
  dataDeps: allDataDependencies !== null && allDataDependencies !== void 0 ? allDataDependencies : [],
71
71
  };
72
+ const variables = {
73
+ variables: {},
74
+ };
75
+ if (appConfig &&
76
+ 'variables' in appConfig &&
77
+ typeof appConfig.variables === 'object' &&
78
+ appConfig.variables !== null) {
79
+ variables.variables = appConfig.variables;
80
+ }
72
81
  // The keys to bundle are the filename without any path information
73
82
  const bundles = Object.keys(bundle).filter((cur) => cur.endsWith('.js'));
74
83
  if (bundles.length === 1) {
75
- return Object.assign(Object.assign(Object.assign({}, _generateManifestEntry(bundle[bundles[0]], extensionPath)), dataDependencies), baseManifest);
84
+ return Object.assign(Object.assign(Object.assign(Object.assign({}, _generateManifestEntry(bundle[bundles[0]], extensionPath)), dataDependencies), baseManifest), variables);
76
85
  }
77
86
  const manifest = bundles.reduce((acc, current) => {
78
87
  return Object.assign(Object.assign({}, acc), { [current]: _generateManifestEntry(bundle[current], extensionPath) });
79
88
  }, {});
80
- return Object.assign(Object.assign(Object.assign({}, manifest), dataDependencies), baseManifest);
89
+ return Object.assign(Object.assign(Object.assign(Object.assign({}, manifest), dataDependencies), baseManifest), variables);
81
90
  }
82
91
  function _generateManifestEntry(subBundle, extensionPath) {
83
92
  const { facadeModuleId, moduleIds, modules } = subBundle;
@@ -130,10 +130,11 @@ export type UnifiedCardConfig = {
130
130
  export declare enum UnifiedComponentTypes {
131
131
  CARD = "CARD",
132
132
  APPLICATION = "APPLICATION",
133
- SETTINGS = "SETTINGS"
133
+ SETTINGS = "SETTINGS",
134
+ PAGE = "PAGE"
134
135
  }
135
136
  export type UnifiedExtensionComponent = Omit<UnifiedCardConfig, 'type'> & {
136
- componentType: UnifiedComponentTypes.CARD | UnifiedComponentTypes.SETTINGS;
137
+ componentType: UnifiedComponentTypes.CARD | UnifiedComponentTypes.SETTINGS | UnifiedComponentTypes.PAGE;
137
138
  componentDeps: {
138
139
  app: string;
139
140
  };
@@ -162,6 +163,9 @@ export interface UnifiedAppComponent {
162
163
  supportUrl: string;
163
164
  supportPhone: string;
164
165
  };
166
+ variables?: {
167
+ [key: string]: string | number | boolean;
168
+ };
165
169
  };
166
170
  componentType: UnifiedComponentTypes.APPLICATION;
167
171
  componentDeps: {};
@@ -175,6 +179,9 @@ export interface UnifiedAppComponent {
175
179
  export type UnifiedAppConfig = Omit<PublicAppConfig, 'auth'> & {
176
180
  auth: UnifiedAppAuth;
177
181
  isPublicApp: boolean;
182
+ variables?: {
183
+ [key: string]: string | number | boolean;
184
+ };
178
185
  };
179
186
  export type UnifiedComponent = UnifiedExtensionComponent | UnifiedAppComponent;
180
187
  export interface UnifiedProjectComponentMap {
@@ -273,5 +280,11 @@ export interface DevModeSetupArguments extends DevModeBaseSetupArguments {
273
280
  }
274
281
  export interface UnifiedDevModeSetupArguments extends DevModeBaseSetupArguments {
275
282
  components: UnifiedProjectComponentMap;
283
+ profileData?: ProfileVariables;
284
+ }
285
+ export type ProfileVariableValue = string | number | boolean;
286
+ export type ProfileVariables = Record<string, ProfileVariableValue>;
287
+ export interface ManifestConfig {
288
+ variables?: ProfileVariables;
276
289
  }
277
290
  export {};
package/dist/lib/types.js CHANGED
@@ -11,4 +11,5 @@ var UnifiedComponentTypes;
11
11
  UnifiedComponentTypes["CARD"] = "CARD";
12
12
  UnifiedComponentTypes["APPLICATION"] = "APPLICATION";
13
13
  UnifiedComponentTypes["SETTINGS"] = "SETTINGS";
14
+ UnifiedComponentTypes["PAGE"] = "PAGE";
14
15
  })(UnifiedComponentTypes || (exports.UnifiedComponentTypes = UnifiedComponentTypes = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions-dev-server",
3
- "version": "0.9.5",
3
+ "version": "0.10.0",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "uie": "./dist/lib/bin/cli.js"
@@ -27,7 +27,7 @@
27
27
  ],
28
28
  "license": "MIT",
29
29
  "dependencies": {
30
- "@hubspot/app-functions-dev-server": "0.9.2",
30
+ "@hubspot/app-functions-dev-server": "0.10.0",
31
31
  "body-parser": "1.20.3",
32
32
  "chalk": "5.4.1",
33
33
  "commander": "13.0.0",
@@ -70,5 +70,5 @@
70
70
  "optional": true
71
71
  }
72
72
  },
73
- "gitHead": "8344193a13ab5874924b02d67413dad052558ecf"
73
+ "gitHead": "34ce86d7cfaa1f163bf67838bbb56c054d0f72cc"
74
74
  }