diff --git a/packages/app/src/cli/services/bundle.ts b/packages/app/src/cli/services/bundle.ts index c3decdbe883..66c7dab10fa 100644 --- a/packages/app/src/cli/services/bundle.ts +++ b/packages/app/src/cli/services/bundle.ts @@ -4,7 +4,7 @@ import {AssetUrlSchema, DeveloperPlatformClient} from '../utilities/developer-pl import {MinimalAppIdentifiers} from '../models/organization.js' import {joinPath} from '@shopify/cli-kit/node/path' import {brotliCompress, zip} from '@shopify/cli-kit/node/archiver' -import {formData, fetch} from '@shopify/cli-kit/node/http' +import {fetch} from '@shopify/cli-kit/node/http' import {readFileSync} from '@shopify/cli-kit/node/fs' import {AbortError} from '@shopify/cli-kit/node/error' import {writeFile} from 'fs/promises' @@ -29,10 +29,8 @@ export async function compressBundle(inputDirectory: string, outputPath: string, * @param filePath - The path to the file */ export async function uploadToGCS(signedURL: string, filePath: string) { - const form = formData() const buffer = readFileSync(filePath) - form.append('my_upload', buffer) - await fetch(signedURL, {method: 'put', body: buffer, headers: form.getHeaders()}, 'slow-request') + await fetch(signedURL, {method: 'put', body: buffer}, 'slow-request') } /** diff --git a/packages/app/src/cli/services/deploy/upload.test.ts b/packages/app/src/cli/services/deploy/upload.test.ts index 7b428edc9de..9c168dbfeb1 100644 --- a/packages/app/src/cli/services/deploy/upload.test.ts +++ b/packages/app/src/cli/services/deploy/upload.test.ts @@ -3,7 +3,6 @@ import {testApp, testDeveloperPlatformClient} from '../../models/app/app.test-da import {AppDeploySchema, AppDeployVariables} from '../../api/graphql/app_deploy.js' import {describe, expect, test, vi} from 'vitest' import {inTemporaryDirectory, writeFile} from '@shopify/cli-kit/node/fs' -import {formData} from '@shopify/cli-kit/node/http' import {joinPath} from '@shopify/cli-kit/node/path' vi.mock('@shopify/cli-kit/node/http') @@ -16,8 +15,6 @@ describe('uploadExtensionsBundle', () => { test('calls a mutation on partners', async () => { await inTemporaryDirectory(async (tmpDir) => { // Given - const mockedFormData = {append: vi.fn(), getHeaders: vi.fn()} - vi.mocked(formData).mockReturnValue(mockedFormData) const developerPlatformClient = testDeveloperPlatformClient() // When @@ -62,8 +59,6 @@ describe('uploadExtensionsBundle', () => { test('calls a mutation on partners with a message and a version', async () => { await inTemporaryDirectory(async (tmpDir) => { // Given - const mockedFormData = {append: vi.fn(), getHeaders: vi.fn()} - vi.mocked(formData).mockReturnValue(mockedFormData) const developerPlatformClient = testDeveloperPlatformClient() // When @@ -111,8 +106,6 @@ describe('uploadExtensionsBundle', () => { test('calls a mutation on partners when there are no extensions', async () => { const developerPlatformClient = testDeveloperPlatformClient() - const mockedFormData = {append: vi.fn(), getHeaders: vi.fn()} - vi.mocked(formData).mockReturnValue(mockedFormData) // When await uploadExtensionsBundle({ appManifest, @@ -222,8 +215,6 @@ describe('uploadExtensionsBundle', () => { deploy: (_input: AppDeployVariables) => Promise.resolve(errorResponse), }) - const mockedFormData = {append: vi.fn(), getHeaders: vi.fn()} - vi.mocked(formData).mockReturnValue(mockedFormData) // When await writeFile(joinPath(tmpDir, 'test.zip'), '') @@ -327,8 +318,6 @@ describe('uploadExtensionsBundle', () => { const developerPlatformClient = testDeveloperPlatformClient({ deploy: (_input: AppDeployVariables) => Promise.resolve(errorResponse), }) - const mockedFormData = {append: vi.fn(), getHeaders: vi.fn()} - vi.mocked(formData).mockReturnValue(mockedFormData) await writeFile(joinPath(tmpDir, 'test.zip'), '') // When diff --git a/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.test.ts b/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.test.ts index b9a89a792b6..447fc40f64e 100644 --- a/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.test.ts +++ b/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.test.ts @@ -14,7 +14,6 @@ import { testWebhookExtensions, } from '../../../../models/app/app.test-data.js' import {getUploadURL} from '../../../bundle.js' -import {formData} from '@shopify/cli-kit/node/http' import {describe, expect, test, vi, beforeEach, afterEach} from 'vitest' import {AbortSignal, AbortController} from '@shopify/cli-kit/node/abort' import {flushPromises} from '@shopify/cli-kit/node/promises' @@ -81,7 +80,6 @@ describe('pushUpdatesForDevSession', () => { let devSessionStatusManager: DevSessionStatusManager beforeEach(() => { - vi.mocked(formData).mockReturnValue({append: vi.fn(), getHeaders: vi.fn()} as any) stdout = {write: vi.fn()} stderr = {write: vi.fn()} developerPlatformClient = testDeveloperPlatformClient() @@ -425,7 +423,6 @@ describe('pushUpdatesForDevSession', () => { test('assetsURL is only generated if affected extensions have assets', async () => { // Given - vi.mocked(formData).mockReturnValue({append: vi.fn(), getHeaders: vi.fn()} as any) // Mock readdir to return that a folder for the extension assets exists vi.mocked(readdir).mockResolvedValue(['other-folders', 'ui-extension-uid']) vi.mocked(getUploadURL).mockResolvedValue('https://gcs.url') @@ -456,7 +453,6 @@ describe('pushUpdatesForDevSession', () => { test('assetsURL is always generated for create, even if there are no assets', async () => { // Given - vi.mocked(formData).mockReturnValue({append: vi.fn(), getHeaders: vi.fn()} as any) vi.mocked(getUploadURL).mockResolvedValue('https://gcs.url') // When diff --git a/packages/cli-kit/package.json b/packages/cli-kit/package.json index bc89c37cbf9..a422d001c6f 100644 --- a/packages/cli-kit/package.json +++ b/packages/cli-kit/package.json @@ -129,7 +129,6 @@ "fast-glob": "3.3.3", "figures": "5.0.0", "find-up": "6.3.0", - "form-data": "4.0.4", "fs-extra": "11.1.0", "get-port-please": "3.1.2", "gradient-string": "2.0.2", diff --git a/packages/cli-kit/src/private/node/api.ts b/packages/cli-kit/src/private/node/api.ts index 6a493350e23..fcffb487df8 100644 --- a/packages/cli-kit/src/private/node/api.ts +++ b/packages/cli-kit/src/private/node/api.ts @@ -3,10 +3,14 @@ import {sanitizeURL} from './api/urls.js' import {sleepWithBackoffUntil} from './sleep-with-backoff.js' import {outputDebug} from '../../public/node/output.js' import {recordRetry} from '../../public/node/analytics.js' -import {Headers} from 'form-data' import {ClientError} from 'graphql-request' import {performance} from 'perf_hooks' +interface ResponseHeaders { + forEach(callback: (value: string, key: string) => void): void + get?(key: string): string | null +} + export type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform' | 'app-management' export const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners', 'business-platform', 'app-management'] @@ -135,7 +139,7 @@ export function isNetworkError(error: unknown): boolean { return false } -async function runRequestWithNetworkLevelRetry( +async function runRequestWithNetworkLevelRetry( requestOptions: RequestOptions, ): Promise { if (!requestOptions.useNetworkLevelRetry) { @@ -164,7 +168,7 @@ async function runRequestWithNetworkLevelRetry( +async function makeVerboseRequest( requestOptions: RequestOptions, ): Promise> { const t0 = performance.now() @@ -264,7 +268,7 @@ function errorsIncludeStatus429(error: ClientError): boolean { return error.response.errors?.some((error) => error.extensions?.code === '429') ?? false } -export async function simpleRequestWithDebugLog( +export async function simpleRequestWithDebugLog( requestOptions: RequestOptions, errorHandler?: (error: unknown, requestId: string | undefined) => unknown, ): Promise { @@ -327,7 +331,7 @@ ${result.sanitizedHeaders} * @param retryOptions - Options for the retry * @returns The response from the request */ -export async function retryAwareRequest( +export async function retryAwareRequest( requestOptions: RequestOptions, errorHandler?: (error: unknown, requestId: string | undefined) => unknown, retryOptions: { diff --git a/packages/cli-kit/src/public/node/http.test.ts b/packages/cli-kit/src/public/node/http.test.ts index f848c4e76a6..057e8f9865c 100644 --- a/packages/cli-kit/src/public/node/http.test.ts +++ b/packages/cli-kit/src/public/node/http.test.ts @@ -1,4 +1,4 @@ -import {downloadFile, shopifyFetch, formData, requestMode, fetch} from './http.js' +import {downloadFile, shopifyFetch, requestMode, fetch} from './http.js' import {mockAndCaptureOutput} from './testing/output.js' import {fileExists, inTemporaryDirectory, readFile} from './fs.js' import {joinPath} from './path.js' @@ -7,7 +7,6 @@ import {platformAndArch} from './os.js' import {afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi} from 'vitest' import {setupServer} from 'msw/node' import {delay, http, HttpResponse} from 'msw' -import FormData from 'form-data' const DURATION_UNTIL_ABORT_IS_SEEN = 100 @@ -76,14 +75,6 @@ afterEach(() => { vi.useRealTimers() }) -describe('formData', () => { - test('make an empty form data object', () => { - const res = formData() - expect(res).toBeInstanceOf(FormData) - expect(res.getLengthSync()).toBe(0) - }) -}) - describe('shopifyFetch', () => { test('make a successful request', async () => { const mockOutput = mockAndCaptureOutput() diff --git a/packages/cli-kit/src/public/node/http.ts b/packages/cli-kit/src/public/node/http.ts index 12c344343e3..c6d81bc6940 100644 --- a/packages/cli-kit/src/public/node/http.ts +++ b/packages/cli-kit/src/public/node/http.ts @@ -8,20 +8,10 @@ import {sanitizeURL} from '../../private/node/api/urls.js' import {outputContent, outputDebug, outputToken} from '../../public/node/output.js' import {NetworkRetryBehaviour, simpleRequestWithDebugLog} from '../../private/node/api.js' import {DEFAULT_MAX_TIME_MS} from '../../private/node/sleep-with-backoff.js' -import FormData from 'form-data' import nodeFetch, {RequestInfo, RequestInit, Response} from 'node-fetch' export {FetchError, Request, Response} from 'node-fetch' -/** - * Create a new FormData object. - * - * @returns A FormData object. - */ -export function formData(): FormData { - return new FormData() -} - type AbortSignal = RequestInit['signal'] type PresetFetchBehaviour = 'default' | 'non-blocking' | 'slow-request'