From 90783d6071341282cbe6bcc325555840c9914a22 Mon Sep 17 00:00:00 2001
From: Joe Yeager <jyeager@hubspot.com>
Date: Mon, 27 Jan 2025 12:43:10 -0800
Subject: [PATCH 1/6] fix: Add missing translation (#1355)

---
 lang/en.lyaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en.lyaml b/lang/en.lyaml
index 7f07353a8..0ba9cc830 100644
--- a/lang/en.lyaml
+++ b/lang/en.lyaml
@@ -1113,7 +1113,6 @@ en:
         notFound: "Your project {{#bold}}{{ projectName }}{{/bold}} could not be found in {{#bold}}{{ accountIdentifier }}{{/bold}}."
       pollFetchProject:
         checkingProject: "Checking if project exists in {{ accountIdentifier }}"
-        unableToFindAutodeployStatus: "Unable to find the auto deploy for build #{{ buildId }}. This deploy may have been skipped. {{ viewDeploysLink }}."
       logFeedbackMessage:
         feedbackHeader: "We'd love to hear your feedback!"
         feedbackMessage: "How are you liking the new projects and developer tools? \n > Run `{{#yellow}}hs feedback{{/yellow}}` to let us know what you think!\n"
@@ -1129,6 +1128,7 @@ en:
         buildSucceededAutomaticallyDeploying: "Build #{{ buildId }} succeeded. {{#bold}}Automatically deploying{{/bold}} to {{ accountIdentifier }}\n"
         cleanedUpTempFile: "Cleaned up temporary file {{ path }}"
         viewDeploys: "View all deploys for this project in HubSpot"
+        unableToFindAutodeployStatus: "Unable to find the auto deploy for build #{{ buildId }}. This deploy may have been skipped. {{ viewDeploysLink }}."
     projectUpload:
       uploadProjectFiles:
         add: "Uploading {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}"

From fbfa8a1c351d830f898512195369088a1a43da8b Mon Sep 17 00:00:00 2001
From: Branden Rodgers <branden@rodgersworld.com>
Date: Mon, 27 Jan 2025 16:05:26 -0500
Subject: [PATCH 2/6] chore: Unit tests for lib/oauth (#1356)

---
 lib/__tests__/oauth.test.ts | 142 ++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100644 lib/__tests__/oauth.test.ts

diff --git a/lib/__tests__/oauth.test.ts b/lib/__tests__/oauth.test.ts
new file mode 100644
index 000000000..2de71816e
--- /dev/null
+++ b/lib/__tests__/oauth.test.ts
@@ -0,0 +1,142 @@
+import express, { Request, Response } from 'express';
+import open from 'open';
+import { OAuth2Manager } from '@hubspot/local-dev-lib/models/OAuth2Manager';
+import { getAccountConfig } from '@hubspot/local-dev-lib/config';
+import { addOauthToAccountConfig } from '@hubspot/local-dev-lib/oauth';
+import { logger } from '@hubspot/local-dev-lib/logger';
+import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
+import { DEFAULT_OAUTH_SCOPES } from '@hubspot/local-dev-lib/constants/auth';
+import { authenticateWithOauth } from '../oauth';
+
+jest.mock('express');
+jest.mock('open');
+jest.mock('@hubspot/local-dev-lib/models/OAuth2Manager');
+jest.mock('@hubspot/local-dev-lib/config');
+jest.mock('@hubspot/local-dev-lib/oauth');
+jest.mock('@hubspot/local-dev-lib/logger');
+
+const mockedExpress = express as unknown as jest.Mock;
+const mockedOAuth2Manager = OAuth2Manager as unknown as jest.Mock;
+const mockedGetAccountConfig = getAccountConfig as jest.Mock;
+
+describe('lib/oauth', () => {
+  const mockExpressReq = {
+    query: { code: 'test-auth-code' },
+  } as unknown as Request;
+  const mockExpressResp = { send: jest.fn() } as unknown as Response;
+
+  const mockAccountConfig = {
+    accountId: 123,
+    clientId: 'test-client-id',
+    clientSecret: 'test-client-secret',
+    scopes: ['test-scope'],
+    env: ENVIRONMENTS.PROD,
+  };
+
+  beforeEach(() => {
+    mockedExpress.mockReturnValue({
+      get: jest.fn().mockImplementation((path, callback) => {
+        if (path === '/oauth-callback') {
+          callback(mockExpressReq, mockExpressResp);
+        }
+      }),
+      listen: jest.fn().mockReturnValue({ close: jest.fn() }),
+    });
+  });
+
+  afterEach(() => {
+    jest.clearAllMocks();
+  });
+
+  describe('authenticateWithOauth()', () => {
+    it('should setup OAuth and authenticate successfully', async () => {
+      // Mock successful OAuth flow
+      const mockOAuth2Manager = {
+        account: mockAccountConfig,
+        exchangeForTokens: jest.fn().mockResolvedValue({}),
+      };
+
+      mockedOAuth2Manager.mockImplementation(() => mockOAuth2Manager);
+      mockedGetAccountConfig.mockReturnValue({
+        env: ENVIRONMENTS.PROD,
+      });
+
+      await authenticateWithOauth(mockAccountConfig);
+
+      // Verify OAuth2Manager was initialized correctly
+      expect(mockedOAuth2Manager).toHaveBeenCalledWith({
+        ...mockAccountConfig,
+        env: ENVIRONMENTS.PROD,
+      });
+
+      // Verify logger was called
+      expect(logger.log).toHaveBeenCalledWith('Authorizing');
+
+      // Verify OAuth tokens were added to config
+      expect(addOauthToAccountConfig).toHaveBeenCalledWith(mockOAuth2Manager);
+    });
+
+    it('should handle missing clientId', async () => {
+      const invalidConfig = {
+        ...mockAccountConfig,
+        clientId: undefined,
+      };
+
+      mockedOAuth2Manager.mockImplementation(() => ({
+        account: invalidConfig,
+      }));
+
+      const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {
+        throw new Error('exit');
+      });
+
+      await expect(authenticateWithOauth(invalidConfig)).rejects.toThrow(
+        'exit'
+      );
+      expect(logger.error).toHaveBeenCalled();
+      expect(exitSpy).toHaveBeenCalled();
+      exitSpy.mockRestore();
+    });
+
+    it('should use default scopes when none provided', async () => {
+      const configWithoutScopes = {
+        ...mockAccountConfig,
+        scopes: undefined,
+      };
+
+      const mockOAuth2Manager = {
+        account: configWithoutScopes,
+        exchangeForTokens: jest.fn().mockResolvedValue({}),
+      };
+
+      mockedOAuth2Manager.mockImplementation(() => mockOAuth2Manager);
+
+      await authenticateWithOauth(configWithoutScopes);
+
+      // Verify default scopes were used
+      expect(open).toHaveBeenCalledWith(
+        expect.stringContaining(
+          encodeURIComponent(DEFAULT_OAUTH_SCOPES.join(' '))
+        ),
+        expect.anything()
+      );
+    });
+
+    it('should handle OAuth exchange failure', async () => {
+      const mockOAuth2Manager = {
+        account: mockAccountConfig,
+        exchangeForTokens: jest
+          .fn()
+          .mockRejectedValue(new Error('Exchange failed')),
+      };
+
+      mockedOAuth2Manager.mockImplementation(() => mockOAuth2Manager);
+
+      await authenticateWithOauth(mockAccountConfig);
+
+      expect(mockExpressResp.send).toHaveBeenCalledWith(
+        expect.stringContaining('Authorization failed')
+      );
+    });
+  });
+});

From 34a2bfdda2c9fc95a3a3941537466dbf841e069e Mon Sep 17 00:00:00 2001
From: Branden Rodgers <branden@rodgersworld.com>
Date: Mon, 27 Jan 2025 17:28:50 -0500
Subject: [PATCH 3/6] chore: unit tests for polling (#1353)

---
 commands/function/deploy.ts    |   4 +-
 commands/project/cloneApp.ts   |   4 +-
 commands/project/migrateApp.ts |   4 +-
 lib/__tests__/polling.test.ts  | 107 +++++++++++++++++++++++++++++++++
 lib/constants.ts               |   9 +--
 lib/polling.ts                 |  46 ++++++++------
 lib/projects/buildAndDeploy.ts |   8 +--
 lib/projects/index.ts          |   4 +-
 8 files changed, 152 insertions(+), 34 deletions(-)
 create mode 100644 lib/__tests__/polling.test.ts

diff --git a/commands/function/deploy.ts b/commands/function/deploy.ts
index 11c2f1f92..f2afea049 100644
--- a/commands/function/deploy.ts
+++ b/commands/function/deploy.ts
@@ -61,7 +61,9 @@ exports.handler = async options => {
       derivedAccountId,
       functionPath
     );
-    const successResp = await poll(getBuildStatus, derivedAccountId, buildId);
+    const successResp = await poll(() =>
+      getBuildStatus(derivedAccountId, buildId)
+    );
     const buildTimeSeconds = (successResp.buildTime / 1000).toFixed(2);
 
     SpinniesManager.succeed('loading');
diff --git a/commands/project/cloneApp.ts b/commands/project/cloneApp.ts
index 5a8ec9535..8a027dd3a 100644
--- a/commands/project/cloneApp.ts
+++ b/commands/project/cloneApp.ts
@@ -104,7 +104,9 @@ exports.handler = async options => {
     const {
       data: { exportId },
     } = await cloneApp(derivedAccountId, appId);
-    const { status } = await poll(checkCloneStatus, derivedAccountId, exportId);
+    const { status } = await poll(() =>
+      checkCloneStatus(derivedAccountId, exportId)
+    );
     if (status === 'SUCCESS') {
       // Ensure correct project folder structure exists
       const baseDestPath = path.resolve(getCwd(), projectDest);
diff --git a/commands/project/migrateApp.ts b/commands/project/migrateApp.ts
index 85b893d18..1380a5878 100644
--- a/commands/project/migrateApp.ts
+++ b/commands/project/migrateApp.ts
@@ -189,7 +189,9 @@ exports.handler = async options => {
       projectName
     );
     const { id } = migrateResponse;
-    const pollResponse = await poll(checkMigrationStatus, derivedAccountId, id);
+    const pollResponse = await poll(() =>
+      checkMigrationStatus(derivedAccountId, id)
+    );
     const { status, project } = pollResponse;
     if (status === 'SUCCESS') {
       const absoluteDestPath = path.resolve(getCwd(), projectDest);
diff --git a/lib/__tests__/polling.test.ts b/lib/__tests__/polling.test.ts
new file mode 100644
index 000000000..45afc1a68
--- /dev/null
+++ b/lib/__tests__/polling.test.ts
@@ -0,0 +1,107 @@
+import { poll, DEFAULT_POLLING_STATES } from '../polling';
+import { DEFAULT_POLLING_DELAY } from '../constants';
+import { HubSpotPromise } from '@hubspot/local-dev-lib/types/Http';
+
+// Mock response types
+type MockResponse = {
+  status: string;
+};
+
+// Helper to create a mock polling callback
+const createMockCallback = (responses: MockResponse[]) => {
+  let callCount = 0;
+  return jest.fn((): HubSpotPromise<{ status: string }> => {
+    const response = responses[callCount];
+    callCount++;
+    return Promise.resolve({ data: response }) as HubSpotPromise<{
+      status: string;
+    }>;
+  });
+};
+
+describe('lib/polling', () => {
+  beforeEach(() => {
+    jest.useFakeTimers();
+  });
+
+  afterEach(() => {
+    jest.useRealTimers();
+  });
+
+  describe('poll()', () => {
+    it('should resolve when status is SUCCESS', async () => {
+      const mockCallback = createMockCallback([
+        { status: DEFAULT_POLLING_STATES.STARTED },
+        { status: DEFAULT_POLLING_STATES.SUCCESS },
+      ]);
+
+      const pollPromise = poll(mockCallback);
+
+      // Fast-forward through two polling intervals
+      jest.advanceTimersByTime(DEFAULT_POLLING_DELAY * 2);
+
+      const result = await pollPromise;
+      expect(result.status).toBe(DEFAULT_POLLING_STATES.SUCCESS);
+      expect(mockCallback).toHaveBeenCalledTimes(2);
+    });
+
+    it('should reject when status is ERROR', async () => {
+      const mockCallback = createMockCallback([
+        { status: DEFAULT_POLLING_STATES.STARTED },
+        { status: DEFAULT_POLLING_STATES.ERROR },
+      ]);
+
+      const pollPromise = poll(mockCallback);
+
+      jest.advanceTimersByTime(DEFAULT_POLLING_DELAY * 2);
+
+      await expect(pollPromise).rejects.toEqual({
+        status: DEFAULT_POLLING_STATES.ERROR,
+      });
+      expect(mockCallback).toHaveBeenCalledTimes(2);
+    });
+
+    it('should reject when status is FAILURE', async () => {
+      const mockCallback = createMockCallback([
+        { status: DEFAULT_POLLING_STATES.STARTED },
+        { status: DEFAULT_POLLING_STATES.FAILURE },
+      ]);
+
+      const pollPromise = poll(mockCallback);
+
+      jest.advanceTimersByTime(DEFAULT_POLLING_DELAY * 2);
+
+      await expect(pollPromise).rejects.toEqual({
+        status: DEFAULT_POLLING_STATES.FAILURE,
+      });
+    });
+
+    it('should reject when status is REVERTED', async () => {
+      const mockCallback = createMockCallback([
+        { status: DEFAULT_POLLING_STATES.STARTED },
+        { status: DEFAULT_POLLING_STATES.REVERTED },
+      ]);
+
+      const pollPromise = poll(mockCallback);
+
+      jest.advanceTimersByTime(DEFAULT_POLLING_DELAY * 2);
+
+      await expect(pollPromise).rejects.toEqual({
+        status: DEFAULT_POLLING_STATES.REVERTED,
+      });
+    });
+
+    it('should reject when callback throws an error', async () => {
+      const mockCallback = jest
+        .fn()
+        .mockRejectedValue(new Error('Network error'));
+
+      const pollPromise = poll(mockCallback);
+
+      jest.advanceTimersByTime(DEFAULT_POLLING_DELAY);
+
+      await expect(pollPromise).rejects.toThrow('Network error');
+      expect(mockCallback).toHaveBeenCalledTimes(1);
+    });
+  });
+});
diff --git a/lib/constants.ts b/lib/constants.ts
index 94c30f6ad..993c6364b 100644
--- a/lib/constants.ts
+++ b/lib/constants.ts
@@ -11,14 +11,7 @@ export const CONFIG_FLAGS = {
   USE_CUSTOM_OBJECT_HUBFILE: 'useCustomObjectHubfile',
 } as const;
 
-export const POLLING_DELAY = 2000;
-
-export const POLLING_STATUS = {
-  SUCCESS: 'SUCCESS',
-  ERROR: 'ERROR',
-  REVERTED: 'REVERTED',
-  FAILURE: 'FAILURE',
-} as const;
+export const DEFAULT_POLLING_DELAY = 2000;
 
 export const PROJECT_CONFIG_FILE = 'hsproject.json' as const;
 
diff --git a/lib/polling.ts b/lib/polling.ts
index baced84f2..3c3a91d78 100644
--- a/lib/polling.ts
+++ b/lib/polling.ts
@@ -1,35 +1,47 @@
 import { HubSpotPromise } from '@hubspot/local-dev-lib/types/Http';
-import { ValueOf } from '@hubspot/local-dev-lib/types/Utils';
-import { POLLING_DELAY, POLLING_STATUS } from './constants';
+import { DEFAULT_POLLING_DELAY } from './constants';
+
+export const DEFAULT_POLLING_STATES = {
+  STARTED: 'STARTED',
+  SUCCESS: 'SUCCESS',
+  ERROR: 'ERROR',
+  REVERTED: 'REVERTED',
+  FAILURE: 'FAILURE',
+} as const;
+
+const DEFAULT_POLLING_STATUS_LOOKUP = {
+  successStates: [DEFAULT_POLLING_STATES.SUCCESS],
+  errorStates: [
+    DEFAULT_POLLING_STATES.ERROR,
+    DEFAULT_POLLING_STATES.REVERTED,
+    DEFAULT_POLLING_STATES.FAILURE,
+  ],
+};
 
 type GenericPollingResponse = {
-  status: ValueOf<typeof POLLING_STATUS>;
+  status: string;
 };
 
-type PollingCallback<T extends GenericPollingResponse> = (
-  accountId: number,
-  taskId: number | string
-) => HubSpotPromise<T>;
+type PollingCallback<T extends GenericPollingResponse> =
+  () => HubSpotPromise<T>;
 
 export function poll<T extends GenericPollingResponse>(
   callback: PollingCallback<T>,
-  accountId: number,
-  taskId: number | string
+  statusLookup: {
+    successStates: string[];
+    errorStates: string[];
+  } = DEFAULT_POLLING_STATUS_LOOKUP
 ): Promise<T> {
   return new Promise((resolve, reject) => {
     const pollInterval = setInterval(async () => {
       try {
-        const { data: pollResp } = await callback(accountId, taskId);
+        const { data: pollResp } = await callback();
         const { status } = pollResp;
 
-        if (status === POLLING_STATUS.SUCCESS) {
+        if (statusLookup.successStates.includes(status)) {
           clearInterval(pollInterval);
           resolve(pollResp);
-        } else if (
-          status === POLLING_STATUS.ERROR ||
-          status === POLLING_STATUS.REVERTED ||
-          status === POLLING_STATUS.FAILURE
-        ) {
+        } else if (statusLookup.errorStates.includes(status)) {
           clearInterval(pollInterval);
           reject(pollResp);
         }
@@ -37,6 +49,6 @@ export function poll<T extends GenericPollingResponse>(
         clearInterval(pollInterval);
         reject(error);
       }
-    }, POLLING_DELAY);
+    }, DEFAULT_POLLING_DELAY);
   });
 }
diff --git a/lib/projects/buildAndDeploy.ts b/lib/projects/buildAndDeploy.ts
index 83f2c5d63..b9841daff 100644
--- a/lib/projects/buildAndDeploy.ts
+++ b/lib/projects/buildAndDeploy.ts
@@ -16,7 +16,7 @@ import {
 import { WarnLogsResponse } from '@hubspot/local-dev-lib/types/Project';
 
 import {
-  POLLING_DELAY,
+  DEFAULT_POLLING_DELAY,
   PROJECT_BUILD_TEXT,
   PROJECT_DEPLOY_TEXT,
   PROJECT_TASK_TYPES,
@@ -366,7 +366,7 @@ function makePollTaskStatusFunc<T extends ProjectTask>({
             resolve(taskStatus);
           }
         }
-      }, POLLING_DELAY);
+      }, DEFAULT_POLLING_DELAY);
     });
   };
 }
@@ -377,7 +377,7 @@ function pollBuildAutodeployStatus(
   buildId: number
 ): Promise<Build> {
   return new Promise((resolve, reject) => {
-    let maxIntervals = (30 * 1000) / POLLING_DELAY; // Num of intervals in ~30s
+    let maxIntervals = (30 * 1000) / DEFAULT_POLLING_DELAY; // Num of intervals in ~30s
 
     const pollInterval = setInterval(async () => {
       let build: Build;
@@ -407,7 +407,7 @@ function pollBuildAutodeployStatus(
       } else {
         maxIntervals -= 1;
       }
-    }, POLLING_DELAY);
+    }, DEFAULT_POLLING_DELAY);
   });
 }
 
diff --git a/lib/projects/index.ts b/lib/projects/index.ts
index 963ca14ae..b73bf1954 100644
--- a/lib/projects/index.ts
+++ b/lib/projects/index.ts
@@ -18,7 +18,7 @@ import { HubSpotPromise } from '@hubspot/local-dev-lib/types/Http';
 
 import {
   FEEDBACK_INTERVAL,
-  POLLING_DELAY,
+  DEFAULT_POLLING_DELAY,
   PROJECT_CONFIG_FILE,
   HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH,
   PROJECT_COMPONENT_TYPES,
@@ -242,7 +242,7 @@ async function pollFetchProject(
           reject(err);
         }
       }
-    }, POLLING_DELAY);
+    }, DEFAULT_POLLING_DELAY);
   });
 }
 

From 1dec46709c973d991dc8820d29afb50cfe47b49d Mon Sep 17 00:00:00 2001
From: Ben Anderson <banderson87@gmail.com>
Date: Mon, 27 Jan 2025 19:11:40 -0500
Subject: [PATCH 4/6] fix: Update @hubspot/ui-extensions-dev-server to 0.8.42
 (#1358)

---
 package.json |   2 +-
 yarn.lock    | 321 +++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 245 insertions(+), 78 deletions(-)

diff --git a/package.json b/package.json
index be85f2311..ebeece2f0 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
     "@hubspot/local-dev-lib": "3.1.3",
     "@hubspot/serverless-dev-runtime": "7.0.1",
     "@hubspot/theme-preview-dev-server": "0.0.10",
-    "@hubspot/ui-extensions-dev-server": "0.8.40",
+    "@hubspot/ui-extensions-dev-server": "0.8.42",
     "archiver": "^7.0.1",
     "chalk": "^4.1.2",
     "chokidar": "^3.0.1",
diff --git a/yarn.lock b/yarn.lock
index 9f7d6f2e4..5fa840ab3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1332,10 +1332,10 @@
   resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62"
   integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==
 
-"@hubspot/api-client@^10.0.0":
-  version "10.2.1"
-  resolved "https://registry.yarnpkg.com/@hubspot/api-client/-/api-client-10.2.1.tgz#c9e21b7f6c0d6a0cdc514b472822c1e494faa80a"
-  integrity sha512-OXZHXag/H7GNyMUP8EB/pdpMUVqb/jDsoRFkoqo+r4PtZiJBse9dKm2Uh+OyHXobV3Mgaad0aWYDiJhD8bjQiw==
+"@hubspot/api-client@10.0.0":
+  version "10.0.0"
+  resolved "https://registry.yarnpkg.com/@hubspot/api-client/-/api-client-10.0.0.tgz#6d9f126c6811ba8195e5b219b98eabddc925702c"
+  integrity sha512-pmKxy3+HFy22jYg3r8M8c8uphHbCg6s1qZHcDMyrci4p6S+shIz3CL6JHyYtI6zTI+I2KZyrzKizEUi1qy5Khw==
   dependencies:
     "@types/node-fetch" "^2.5.7"
     bottleneck "^2.19.5"
@@ -1346,18 +1346,18 @@
     node-fetch "^2.6.0"
     url-parse "^1.4.3"
 
-"@hubspot/app-functions-dev-server@0.8.40":
-  version "0.8.40"
-  resolved "https://registry.yarnpkg.com/@hubspot/app-functions-dev-server/-/app-functions-dev-server-0.8.40.tgz#48a6f650d1a9aab86f38b21f32b1993abc62d9f8"
-  integrity sha512-Lq06p7fRTj9WFFNN381hZ8NcEz7OhA/IPEdJPVdLh+uS0OHywXLsVgJck2lvysi8rEqP6JOq1BHIz0d7ZvZtoA==
+"@hubspot/app-functions-dev-server@0.8.42":
+  version "0.8.42"
+  resolved "https://registry.yarnpkg.com/@hubspot/app-functions-dev-server/-/app-functions-dev-server-0.8.42.tgz#50da25bdc29d091ef881851997488fadbf0c3076"
+  integrity sha512-80oS4bS0zVO3FMWqOX0P29bJwCjpxU+gDRteyRTyxIpyKwIj4SONE3jmoPfdJLXDuJy53Zr7fIA18rRyq8ThQw==
   dependencies:
-    "@hubspot/api-client" "^10.0.0"
-    axios "^1.6.8"
-    cors "^2.8.5"
-    dotenv "^16.3.1"
-    express "^4.18.2"
-    moment "^2.29.4"
-    uuid "^9.0.1"
+    "@hubspot/api-client" "10.0.0"
+    axios "1.6.8"
+    cors "2.8.5"
+    dotenv "16.3.1"
+    express "4.18.2"
+    moment "2.30.1"
+    uuid "9.0.1"
 
 "@hubspot/cms-components@^0.18.11":
   version "0.18.11"
@@ -1497,21 +1497,21 @@
     express "^4.18.2"
     node-fetch "2.7.0"
 
-"@hubspot/ui-extensions-dev-server@0.8.40":
-  version "0.8.40"
-  resolved "https://registry.yarnpkg.com/@hubspot/ui-extensions-dev-server/-/ui-extensions-dev-server-0.8.40.tgz#9b6c72468bd743a945f67cfa0aa4d4323d800350"
-  integrity sha512-KlbwG/yHl9l6ubttCMpI/R93d9aZaQB40X0u9ME672AryVMr3MXLJDu9InCsOkvt5cO8/wRtMHcQyNmeCub3+g==
+"@hubspot/ui-extensions-dev-server@0.8.42":
+  version "0.8.42"
+  resolved "https://registry.yarnpkg.com/@hubspot/ui-extensions-dev-server/-/ui-extensions-dev-server-0.8.42.tgz#e01d3be5e7da5aa10f49e06b48e68585fcef166a"
+  integrity sha512-CeagEF658JvuZJl04NHxtTE8EqTRq0g3B6l9NGJ+/F7EoaVduQ7hfPmeS5zhYx85f58prtUwTyp/aHpDoAxNlQ==
   dependencies:
-    "@hubspot/app-functions-dev-server" "0.8.40"
-    chalk "^5.4.1"
-    commander "^13.0.0"
-    cors "^2.8.5"
+    "@hubspot/app-functions-dev-server" "0.8.42"
+    chalk "5.4.1"
+    commander "13.0.0"
+    cors "2.8.5"
     detect-port "1.5.1"
-    estraverse "^5.3.0"
-    express "^4.18.2"
+    estraverse "5.3.0"
+    express "4.18.2"
     inquirer "8.2.0"
-    ora "^8.1.1"
-    vite "^4.4.9"
+    ora "8.1.1"
+    vite "4.5.5"
 
 "@humanwhocodes/config-array@^0.13.0":
   version "0.13.0"
@@ -4246,7 +4246,16 @@ aws4@^1.8.0:
   resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef"
   integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==
 
-axios@^1.2.2, axios@^1.3.5, axios@^1.6.8, axios@^1.7.2:
+axios@1.6.8:
+  version "1.6.8"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66"
+  integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==
+  dependencies:
+    follow-redirects "^1.15.6"
+    form-data "^4.0.0"
+    proxy-from-env "^1.1.0"
+
+axios@^1.2.2, axios@^1.3.5, axios@^1.7.2:
   version "1.7.9"
   resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a"
   integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==
@@ -4425,6 +4434,24 @@ bl@^4.0.3, bl@^4.1.0:
     inherits "^2.0.4"
     readable-stream "^3.4.0"
 
+body-parser@1.20.1:
+  version "1.20.1"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
+  integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
+  dependencies:
+    bytes "3.1.2"
+    content-type "~1.0.4"
+    debug "2.6.9"
+    depd "2.0.0"
+    destroy "1.2.0"
+    http-errors "2.0.0"
+    iconv-lite "0.4.24"
+    on-finished "2.4.1"
+    qs "6.11.0"
+    raw-body "2.5.1"
+    type-is "~1.6.18"
+    unpipe "1.0.0"
+
 body-parser@1.20.3, body-parser@^1.19.0:
   version "1.20.3"
   resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
@@ -4645,6 +4672,11 @@ caseless@~0.12.0:
   resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
   integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
 
+chalk@5.4.1:
+  version "5.4.1"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8"
+  integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==
+
 chalk@^2.4.2:
   version "2.4.2"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -4667,11 +4699,6 @@ chalk@^5.3.0:
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.0.tgz#846fdb5d5d939d6fa3d565cd5545697b6f8b6923"
   integrity sha512-ZkD35Mx92acjB2yNJgziGqT9oKHEOxjTBTDRpOsRWtdecL/0jM3z5kM/CTzHWvHIen1GvkM85p6TuFfDGfc8/Q==
 
-chalk@^5.4.1:
-  version "5.4.1"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8"
-  integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==
-
 char-regex@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
@@ -4894,16 +4921,16 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
   dependencies:
     delayed-stream "~1.0.0"
 
+commander@13.0.0:
+  version "13.0.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-13.0.0.tgz#1b161f60ee3ceb8074583a0f95359a4f8701845c"
+  integrity sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==
+
 commander@^12.0.0, commander@^12.1.0:
   version "12.1.0"
   resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
   integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
 
-commander@^13.0.0:
-  version "13.0.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-13.0.0.tgz#1b161f60ee3ceb8074583a0f95359a4f8701845c"
-  integrity sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==
-
 commander@^2.19.0:
   version "2.20.3"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@@ -5019,6 +5046,11 @@ cookie-signature@1.0.6:
   resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
   integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
 
+cookie@0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
+  integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+
 cookie@0.7.1:
   version "0.7.1"
   resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
@@ -5046,7 +5078,7 @@ core-util-is@~1.0.0:
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
   integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
 
-cors@^2.8.5:
+cors@2.8.5, cors@^2.8.5:
   version "2.8.5"
   resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
   integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
@@ -5539,7 +5571,12 @@ dotenv-expand@^10.0.0:
   resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37"
   integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==
 
-dotenv@^16.0.0, dotenv@^16.3.1:
+dotenv@16.3.1:
+  version "16.3.1"
+  resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
+  integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
+
+dotenv@^16.0.0:
   version "16.4.7"
   resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26"
   integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==
@@ -6167,7 +6204,7 @@ esrecurse@^4.3.0:
   dependencies:
     estraverse "^5.2.0"
 
-estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
+estraverse@5.3.0, estraverse@^5.1.0, estraverse@^5.2.0:
   version "5.3.0"
   resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
   integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
@@ -6279,6 +6316,43 @@ expect@^29.0.0, expect@^29.7.0:
     jest-message-util "^29.7.0"
     jest-util "^29.7.0"
 
+express@4.18.2:
+  version "4.18.2"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
+  integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
+  dependencies:
+    accepts "~1.3.8"
+    array-flatten "1.1.1"
+    body-parser "1.20.1"
+    content-disposition "0.5.4"
+    content-type "~1.0.4"
+    cookie "0.5.0"
+    cookie-signature "1.0.6"
+    debug "2.6.9"
+    depd "2.0.0"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    finalhandler "1.2.0"
+    fresh "0.5.2"
+    http-errors "2.0.0"
+    merge-descriptors "1.0.1"
+    methods "~1.1.2"
+    on-finished "2.4.1"
+    parseurl "~1.3.3"
+    path-to-regexp "0.1.7"
+    proxy-addr "~2.0.7"
+    qs "6.11.0"
+    range-parser "~1.2.1"
+    safe-buffer "5.2.1"
+    send "0.18.0"
+    serve-static "1.15.0"
+    setprototypeof "1.2.0"
+    statuses "2.0.1"
+    type-is "~1.6.18"
+    utils-merge "1.0.1"
+    vary "~1.1.2"
+
 express@^4.17.1, express@^4.17.3, express@^4.18.2:
   version "4.21.2"
   resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32"
@@ -6484,6 +6558,19 @@ fill-range@^7.1.1:
   dependencies:
     to-regex-range "^5.0.1"
 
+finalhandler@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
+  integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
+  dependencies:
+    debug "2.6.9"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    on-finished "2.4.1"
+    parseurl "~1.3.3"
+    statuses "2.0.1"
+    unpipe "~1.0.0"
+
 finalhandler@1.3.1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019"
@@ -8678,6 +8765,11 @@ memoizerific@^1.11.3:
   dependencies:
     map-or-similar "^1.5.0"
 
+merge-descriptors@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+  integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
+
 merge-descriptors@1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
@@ -8866,7 +8958,7 @@ module-lookup-amd@^9.0.1:
     requirejs "^2.3.7"
     requirejs-config-file "^4.0.0"
 
-moment@^2.29.1, moment@^2.29.4:
+moment@2.30.1, moment@^2.29.1, moment@^2.29.4:
   version "2.30.1"
   resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
   integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==
@@ -9182,6 +9274,21 @@ optionator@^0.9.3:
     type-check "^0.4.0"
     word-wrap "^1.2.5"
 
+ora@8.1.1:
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/ora/-/ora-8.1.1.tgz#8efc8865e44c87e4b55468a47e80a03e678b0e54"
+  integrity sha512-YWielGi1XzG1UTvOaCFaNgEnuhZVMSHYkW/FQ7UX8O26PtlpdM84c0f7wLPlkvx2RfiQmnzd61d/MGxmpQeJPw==
+  dependencies:
+    chalk "^5.3.0"
+    cli-cursor "^5.0.0"
+    cli-spinners "^2.9.2"
+    is-interactive "^2.0.0"
+    is-unicode-supported "^2.0.0"
+    log-symbols "^6.0.0"
+    stdin-discarder "^0.2.2"
+    string-width "^7.2.0"
+    strip-ansi "^7.1.0"
+
 ora@^5.4.1:
   version "5.4.1"
   resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
@@ -9197,21 +9304,6 @@ ora@^5.4.1:
     strip-ansi "^6.0.0"
     wcwidth "^1.0.1"
 
-ora@^8.1.1:
-  version "8.1.1"
-  resolved "https://registry.yarnpkg.com/ora/-/ora-8.1.1.tgz#8efc8865e44c87e4b55468a47e80a03e678b0e54"
-  integrity sha512-YWielGi1XzG1UTvOaCFaNgEnuhZVMSHYkW/FQ7UX8O26PtlpdM84c0f7wLPlkvx2RfiQmnzd61d/MGxmpQeJPw==
-  dependencies:
-    chalk "^5.3.0"
-    cli-cursor "^5.0.0"
-    cli-spinners "^2.9.2"
-    is-interactive "^2.0.0"
-    is-unicode-supported "^2.0.0"
-    log-symbols "^6.0.0"
-    stdin-discarder "^0.2.2"
-    string-width "^7.2.0"
-    strip-ansi "^7.1.0"
-
 os-tmpdir@~1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -9391,6 +9483,11 @@ path-to-regexp@0.1.12:
   resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7"
   integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==
 
+path-to-regexp@0.1.7:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+  integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
+
 path-type@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
@@ -9698,6 +9795,13 @@ pure-rand@^6.0.0:
   resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2"
   integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==
 
+qs@6.11.0:
+  version "6.11.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
+  integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
+  dependencies:
+    side-channel "^1.0.4"
+
 qs@6.13.0:
   version "6.13.0"
   resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
@@ -9747,6 +9851,16 @@ range-parser@~1.2.1:
   resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
   integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
 
+raw-body@2.5.1:
+  version "2.5.1"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
+  integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
+  dependencies:
+    bytes "3.1.2"
+    http-errors "2.0.0"
+    iconv-lite "0.4.24"
+    unpipe "1.0.0"
+
 raw-body@2.5.2:
   version "2.5.2"
   resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
@@ -10386,6 +10500,25 @@ semver@~7.0.0:
   resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
   integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
 
+send@0.18.0:
+  version "0.18.0"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
+  integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
+  dependencies:
+    debug "2.6.9"
+    depd "2.0.0"
+    destroy "1.2.0"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "2.0.0"
+    mime "1.6.0"
+    ms "2.1.3"
+    on-finished "2.4.1"
+    range-parser "~1.2.1"
+    statuses "2.0.1"
+
 send@0.19.0:
   version "0.19.0"
   resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
@@ -10416,6 +10549,16 @@ serve-favicon@^2.5.0:
     parseurl "~1.3.2"
     safe-buffer "5.1.1"
 
+serve-static@1.15.0:
+  version "1.15.0"
+  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
+  integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
+  dependencies:
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    parseurl "~1.3.3"
+    send "0.18.0"
+
 serve-static@1.16.2:
   version "1.16.2"
   resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296"
@@ -10709,7 +10852,16 @@ string-length@^4.0.1:
     char-regex "^1.0.2"
     strip-ansi "^6.0.0"
 
-"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
+"string-width-cjs@npm:string-width@^4.2.0":
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+  dependencies:
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.1"
+
+string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
   version "4.2.3"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
   integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -10791,7 +10943,7 @@ stringify-object@^3.2.1, stringify-object@^3.3.0:
     is-obj "^1.0.1"
     is-regexp "^1.0.0"
 
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
   integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -10805,6 +10957,13 @@ strip-ansi@^5.2.0:
   dependencies:
     ansi-regex "^4.1.0"
 
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+  dependencies:
+    ansi-regex "^5.0.1"
+
 strip-ansi@^7.0.1, strip-ansi@^7.1.0:
   version "7.1.0"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -11570,16 +11729,16 @@ utils-merge@1.0.1:
   resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
   integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
 
+uuid@9.0.1, uuid@^9.0.0:
+  version "9.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
+  integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
+
 uuid@^3.3.2:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
   integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
 
-uuid@^9.0.0, uuid@^9.0.1:
-  version "9.0.1"
-  resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
-  integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
-
 v8-compile-cache-lib@^3.0.1:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
@@ -11637,6 +11796,17 @@ vite-plugin-mkcert@1.16.0:
     debug "^4.3.4"
     picocolors "^1.0.0"
 
+vite@4.5.5:
+  version "4.5.5"
+  resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.5.tgz#639b9feca5c0a3bfe3c60cb630ef28bf219d742e"
+  integrity sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==
+  dependencies:
+    esbuild "^0.18.10"
+    postcss "^8.4.27"
+    rollup "^3.27.1"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
 vite@5.4.8:
   version "5.4.8"
   resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8"
@@ -11648,17 +11818,6 @@ vite@5.4.8:
   optionalDependencies:
     fsevents "~2.3.3"
 
-vite@^4.4.9:
-  version "4.5.5"
-  resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.5.tgz#639b9feca5c0a3bfe3c60cb630ef28bf219d742e"
-  integrity sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==
-  dependencies:
-    esbuild "^0.18.10"
-    postcss "^8.4.27"
-    rollup "^3.27.1"
-  optionalDependencies:
-    fsevents "~2.3.2"
-
 w3c-xmlserializer@^5.0.0:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c"
@@ -11829,8 +11988,7 @@ wordwrap@^1.0.0:
   resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
   integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
 
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
-  name wrap-ansi-cjs
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
   integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -11848,6 +12006,15 @@ wrap-ansi@^6.2.0:
     string-width "^4.1.0"
     strip-ansi "^6.0.0"
 
+wrap-ansi@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+  dependencies:
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
+
 wrap-ansi@^8.1.0:
   version "8.1.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"

From 919678fa7fd3930deedeb91a8fb91fb3558495a4 Mon Sep 17 00:00:00 2001
From: Joe Yeager <jyeager@hubspot.com>
Date: Mon, 27 Jan 2025 16:15:26 -0800
Subject: [PATCH 5/6] v7.0.2-beta.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index ebeece2f0..fa80b2679 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@hubspot/cli",
-  "version": "7.0.1",
+  "version": "7.0.2-beta.0",
   "description": "The official CLI for developing on HubSpot",
   "license": "Apache-2.0",
   "repository": "https://github.com/HubSpot/hubspot-cli",

From 81229c1147f80f2b8eb11854aecc126d9435ff2d Mon Sep 17 00:00:00 2001
From: Joe Yeager <jyeager@hubspot.com>
Date: Tue, 28 Jan 2025 14:23:55 -0800
Subject: [PATCH 6/6] v7.0.2

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index fa80b2679..05ddbb608 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@hubspot/cli",
-  "version": "7.0.2-beta.0",
+  "version": "7.0.2",
   "description": "The official CLI for developing on HubSpot",
   "license": "Apache-2.0",
   "repository": "https://github.com/HubSpot/hubspot-cli",