From f61e780321a96807655027b7a02f9ca0a05dc661 Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Thu, 2 Oct 2025 12:38:06 -0400 Subject: [PATCH 01/14] sync cloud validations in server on postinstall --- packages/server/.gitignore | 1 + packages/server/package.json | 9 +- .../server/scripts/sync-cloud-validations.sh | 108 ++++++++++++++++++ 3 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 packages/server/.gitignore create mode 100755 packages/server/scripts/sync-cloud-validations.sh diff --git a/packages/server/.gitignore b/packages/server/.gitignore new file mode 100644 index 00000000000..e691b590355 --- /dev/null +++ b/packages/server/.gitignore @@ -0,0 +1 @@ +lib/validations diff --git a/packages/server/package.json b/packages/server/package.json index 2e18327c3c5..53251da55fd 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -10,7 +10,7 @@ "codecov": "codecov", "dev": "node index.js", "docker": "cd ../.. && WORKING_DIR=/packages/server ./scripts/run-docker-local.sh", - "postinstall": "patch-package", + "postinstall": "patch-package && yarn sync-cloud-validations", "lint": "eslint", "rebuild-better-sqlite3": "electron-rebuild -f -o better-sqlite3", "repl": "node repl.js", @@ -19,7 +19,9 @@ "test-integration": "node ./test/scripts/run.js --glob-in-dir=test/integration", "test-performance": "node ./test/scripts/run.js --glob-in-dir=test/performance", "test-unit": "node ./test/scripts/run.js --glob-in-dir=test/unit", - "test-watch": "./test/scripts/watch test" + "test-watch": "./test/scripts/watch test", + "sync-cloud-validations": "./scripts/sync-cloud-validations.sh sync", + "ensure-cloud-validations": "./scripts/sync-cloud-validations.sh" }, "dependencies": { "@babel/parser": "7.28.0", @@ -211,7 +213,8 @@ "tsconfig-paths": "3.10.1", "webpack": "^5.88.2", "ws": "5.2.4", - "xvfb-maybe": "0.2.1" + "xvfb-maybe": "0.2.1", + "zod": "^3.24.2" }, "files": [ "config", diff --git a/packages/server/scripts/sync-cloud-validations.sh b/packages/server/scripts/sync-cloud-validations.sh new file mode 100755 index 00000000000..748e6f64ad6 --- /dev/null +++ b/packages/server/scripts/sync-cloud-validations.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +# Script to sync cloud validations for the server package +# This ensures we have up-to-date TypeScript definitions for API operations + +set -e + +INTERNAL_CLOUD_ENV=${CYPRESS_INTERNAL_ENV:-production} + +case $INTERNAL_CLOUD_ENV in + test) VALIDATION_BASE="https://api.cypress.io" ;; + production) VALIDATION_BASE="https://api.cypress.io" ;; + staging) VALIDATION_BASE="https://api-staging.cypress.io" ;; + development) VALIDATION_BASE="http://localhost:1234" ;; + *) VALIDATION_BASE="https://api.cypress.io" ;; +esac + +# Output to packages/server/lib/validations +OUTPUT_FOLDER="$(dirname "$0")/../lib/validations" +JS_FILE="$OUTPUT_FOLDER/cloudValidations.js" +DTS_FILE="$OUTPUT_FOLDER/cloudValidations.d.ts" + + +sync_cloud_validations() { + echo "Syncing cloud validations from $VALIDATION_BASE..." + + # Create output directory if it doesn't exist + mkdir -p "$OUTPUT_FOLDER" + + # Download validations with headers + echo "Downloading validations..." + curl -s -D /tmp/validations_headers "$VALIDATION_BASE/cypress-app/validations" > "$JS_FILE" + + echo "Downloading types..." + curl -s -D /tmp/types_headers "$VALIDATION_BASE/cypress-app/validations/types" > "$DTS_FILE" + + # Extract ETag headers + VALIDATIONS_ETAG=$(grep -i "etag:" /tmp/validations_headers | cut -d' ' -f2 | tr -d '\r\n') + TYPES_ETAG=$(grep -i "etag:" /tmp/types_headers | cut -d' ' -f2 | tr -d '\r\n') + + # Add ETag as comment to the files + { + echo "// ETag: $VALIDATIONS_ETAG" + echo "// Last-Synced: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" + echo "" + cat "$JS_FILE" + } > "$JS_FILE.tmp" && mv "$JS_FILE.tmp" "$JS_FILE" + + { + echo "// ETag: $TYPES_ETAG" + echo "// Last-Synced: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" + echo "" + cat "$DTS_FILE" + } > "$DTS_FILE.tmp" && mv "$DTS_FILE.tmp" "$DTS_FILE" + + # Clean up temp files + rm -f /tmp/validations_headers /tmp/types_headers + + echo "✅ Cloud validations synced successfully" +} + +ensure_cloud_validations() { + if [[ ! -f "$JS_FILE" || ! -f "$DTS_FILE" ]]; then + echo "Cloud validation files missing, syncing..." + if ! sync_cloud_validations; then + echo "❌ Failed to sync cloud validations. Build may fail without these files." + exit 1 + fi + return + fi + + # Extract stored ETags from the files + STORED_JS_ETAG=$(head -n 1 "$JS_FILE" | sed 's|// ETag: ||' | tr -d '\r\n') + STORED_DTS_ETAG=$(head -n 1 "$DTS_FILE" | sed 's|// ETag: ||' | tr -d '\r\n') + + echo "Checking if cloud validations are up to date..." + + # Get current ETags without downloading the full content + # If we can't fetch ETags (offline), just use existing files + CURRENT_JS_ETAG=$(curl -s -I "$VALIDATION_BASE/cypress-app/validations" 2>/dev/null | grep -i "etag:" | cut -d' ' -f2 | tr -d '\r\n') + CURRENT_DTS_ETAG=$(curl -s -I "$VALIDATION_BASE/cypress-app/validations/types" 2>/dev/null | grep -i "etag:" | cut -d' ' -f2 | tr -d '\r\n') + + # If we couldn't fetch ETags (offline), use existing files + if [[ -z "$CURRENT_JS_ETAG" || -z "$CURRENT_DTS_ETAG" ]]; then + echo "⚠️ Could not check ETags (offline?), using existing files" + return + fi + + # Compare ETags + if [[ "$STORED_JS_ETAG" != "$CURRENT_JS_ETAG" || "$STORED_DTS_ETAG" != "$CURRENT_DTS_ETAG" ]]; then + echo "Cloud validation files are outdated (ETags changed), syncing..." + if ! sync_cloud_validations; then + echo "⚠️ Failed to sync, but existing files will be used" + fi + else + echo "✅ Cloud validation files are up to date (ETags match)" + fi +} + +# Run the appropriate function based on command line arguments +case "${1:-}" in + sync) + sync_cloud_validations + ;; + *) + ensure_cloud_validations + ;; +esac From b35c26e32849927a21c13e58eb2b616e129ab2ff Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Thu, 2 Oct 2025 12:38:34 -0400 Subject: [PATCH 02/14] use cloud validation types in api calls --- .../server/lib/cloud/api/create_instance.ts | 28 ++---- packages/server/lib/cloud/api/index.ts | 93 +++++++------------ yarn.lock | 2 +- 3 files changed, 43 insertions(+), 80 deletions(-) diff --git a/packages/server/lib/cloud/api/create_instance.ts b/packages/server/lib/cloud/api/create_instance.ts index 4ef74f73d3e..f1ea5f965ee 100644 --- a/packages/server/lib/cloud/api/create_instance.ts +++ b/packages/server/lib/cloud/api/create_instance.ts @@ -3,29 +3,13 @@ import { asyncRetry, exponentialBackoff } from '../../util/async_retry' import * as errors from '../../errors' import { isAxiosError } from 'axios' -const MAX_RETRIES = 3 - -export interface CreateInstanceResponse { - spec: string | null - instanceId: string | null - claimedInstances: number - estimatedWallClockDuration: number | null - totalInstances: number -} +// Import cloud validation types for better type safety +import type { + PostRunInstanceRequest_v2Type as CreateInstanceRequestBody, + PostRunInstanceResponse_v2 as CreateInstanceResponse, +} from '../../validations/cloudValidations' -export interface CreateInstanceRequestBody { - spec: string | null - groupId: string - machineId: string - platform: { - browserName: string - browserVersion: string - osCpus: any[] - osMemory: Record | null - osName: string - osVersion: string - } -} +const MAX_RETRIES = 3 export const createInstance = async (runId: string, instanceData: CreateInstanceRequestBody, timeout: number = 0): Promise => { let attemptNumber = 0 diff --git a/packages/server/lib/cloud/api/index.ts b/packages/server/lib/cloud/api/index.ts index df307ce5be4..f8100695875 100644 --- a/packages/server/lib/cloud/api/index.ts +++ b/packages/server/lib/cloud/api/index.ts @@ -30,14 +30,25 @@ import type { ProjectBase } from '../../project-base' import { PUBLIC_KEY_VERSION } from '../constants' -// axios implementation disabled until proxy issues can be diagnosed/fixed -// TODO: https://github.com/cypress-io/cypress/issues/31490 -//import { createInstance } from './create_instance' -import type { CreateInstanceRequestBody, CreateInstanceResponse } from './create_instance' - import { transformError } from './axios_middleware/transform_error' import { DecryptionError } from './cloud_request_errors' +// Import cloud validation types for better type safety +import type { + PostRunRequest_v3Type as CreateRunRequestType, + PostRunResponse_v3Type as CreateRunResponseType, + PostRunInstanceRequest_v2Type as CreateInstanceRequestType, + PostRunInstanceResponse_v2 as CreateInstanceResponse, + PostInstanceResultsRequest_v1Type as PostInstanceResultsRequestType, + PostInstanceResultsResponse_v1Type as PostInstanceResultsResponseType, + PostInstanceTestsResponse_v1Type as PostInstanceTestsResponseType, + PutInstanceResponse_v2Type as UpdateInstanceStdoutResponseType, + PutInstanceStdoutRequest_v1Type as UpdateInstanceStdoutRequestType, +} from '../../validations/cloudValidations' + +// Define response type for putInstanceArtifacts (returns z.ZodAny with resExample: {}) +type PutInstanceArtifactsResponseType = any + const THIRTY_SECONDS = humanInterval('30 seconds') const SIXTY_SECONDS = humanInterval('60 seconds') const TWO_MINUTES = humanInterval('2 minutes') @@ -242,47 +253,15 @@ function noProxyPreflightTimeout (): number { } } -export type CreateRunOptions = { +// Use cloud validation types for better type safety +export type CreateRunOptions = CreateRunRequestType & { projectRoot: string - ci: { - params: string - provider: string - } - ciBuildId: string - projectId: string - recordKey: string - commit: string - specs: string[] - group: string - platform: string - parallel: boolean - specPattern: string[] - tags: string[] - testingType: 'e2e' | 'component' - timeout?: number project: ProjectBase - autoCancelAfterFailures?: number | undefined + timeout?: number } -type CreateRunResponse = { - groupId: string - machineId: string - runId: string - tags: string[] | null - runUrl: string - warnings: (Record & { - code: string - message: string - name: string - })[] - captureProtocolUrl?: string | undefined - capture?: { - url?: string - tags: string[] | null - mountVersion?: number - disabledMessage?: string - } | undefined -} +// Use cloud validation types for better type safety +type CreateRunResponse = CreateRunResponseType export type ArtifactMetadata = { url: string @@ -341,26 +320,26 @@ export default { rp, // For internal testing - setPreflightResult (toSet) { + setPreflightResult (toSet: any): void { preflightResult = { ...preflightResult, ...toSet, } }, - resetPreflightResult () { + resetPreflightResult (): void { recordRoutes = apiRoutes preflightResult = { encrypt: true, } }, - ping () { + ping (): Bluebird { return rp.get(apiRoutes.ping()) .catch(tagError) }, - getAuthUrls () { + getAuthUrls (): Bluebird { return rp.get({ url: apiRoutes.auth(), json: true, @@ -446,7 +425,7 @@ export default { } } - if (script) { + if (script && options.testingType === 'e2e' || options.testingType === 'component') { const config = options.project.getConfig() await options.project.protocolManager.prepareAndSetupProtocol(script, { @@ -471,7 +450,7 @@ export default { .catch(tagError) }, - createInstance (runId: string, body: CreateInstanceRequestBody, timeout?: number): Bluebird { + createInstance (runId: string, body: CreateInstanceRequestType, timeout?: number): Bluebird { return retryWithBackoff((attemptIndex) => { return rp.post({ body, @@ -490,7 +469,7 @@ export default { }) as Bluebird }, - postInstanceTests (options) { + postInstanceTests (options: { instanceId: string, runId: string, timeout?: number, [key: string]: any }): Bluebird { const { instanceId, runId, timeout, ...body } = options return retryWithBackoff((attemptIndex) => { @@ -511,7 +490,7 @@ export default { }) }, - updateInstanceStdout (options) { + updateInstanceStdout (options: UpdateInstanceStdoutRequestType & { instanceId: string, runId: string, timeout?: number }): Bluebird { return retryWithBackoff((attemptIndex) => { return rp.put({ url: recordRoutes.instanceStdout(options.instanceId), @@ -531,7 +510,7 @@ export default { }) }, - updateInstanceArtifacts (options: UpdateInstanceArtifactsOptions, body: UpdateInstanceArtifactsPayload) { + updateInstanceArtifacts (options: UpdateInstanceArtifactsOptions, body: UpdateInstanceArtifactsPayload): Bluebird { debug('PUT %s %o', recordRoutes.instanceArtifacts(options.instanceId), body) return retryWithBackoff((attemptIndex) => { @@ -551,7 +530,7 @@ export default { }) }, - postInstanceResults (options) { + postInstanceResults (options: PostInstanceResultsRequestType & { instanceId: string, runId: string, timeout?: number }): Bluebird { return retryWithBackoff((attemptIndex) => { return rp.post({ url: recordRoutes.instanceResults(options.instanceId), @@ -578,7 +557,7 @@ export default { }) }, - createCrashReport (body, authToken, timeout = 3000) { + createCrashReport (body: any, authToken: string, timeout = 3000): Bluebird { return rp.post({ url: apiRoutes.exceptions(), json: true, @@ -591,7 +570,7 @@ export default { .catch(tagError) }, - postLogout (authToken) { + postLogout (authToken: string): Bluebird { return Bluebird.join( this.getAuthUrls(), machineId.machineId(), @@ -612,11 +591,11 @@ export default { ) }, - clearCache () { + clearCache (): void { responseCache = {} }, - sendPreflight (preflightInfo) { + sendPreflight (preflightInfo: any): Bluebird { return retryWithBackoff(async (attemptIndex) => { const { projectRoot, timeout, ...preflightRequestBody } = preflightInfo @@ -674,7 +653,7 @@ export default { }) }, - async getCaptureProtocolScript (url: string) { + async getCaptureProtocolScript (url: string): Promise { // TODO(protocol): Ensure this is removed in production if (process.env.CYPRESS_LOCAL_PROTOCOL_PATH) { debugProtocol(`Loading protocol via script at local path %s`, process.env.CYPRESS_LOCAL_PROTOCOL_PATH) diff --git a/yarn.lock b/yarn.lock index 772705345ad..f32b51e48b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34470,7 +34470,7 @@ zod@3.25.75: resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.75.tgz#8ff9be2fbbcb381a9236f9f74a8879ca29dcc504" integrity sha512-OhpzAmVzabPOL6C3A3gpAifqr9MqihV/Msx3gor2b2kviCgcb+HM9SEOpMWwwNp9MRunWnhtAKUoo0AHhjyPPg== -zod@^3.22.5, zod@^3.23.8: +zod@^3.22.5, zod@^3.23.8, zod@^3.24.2: version "3.25.76" resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== From f7a85d5ee3b9f3711b19f6426793a17716eac2a6 Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Thu, 2 Oct 2025 12:46:36 -0400 Subject: [PATCH 03/14] only download dts --- .../server/scripts/sync-cloud-validations.sh | 49 ++++++++----------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/packages/server/scripts/sync-cloud-validations.sh b/packages/server/scripts/sync-cloud-validations.sh index 748e6f64ad6..cb9e50e4b07 100755 --- a/packages/server/scripts/sync-cloud-validations.sh +++ b/packages/server/scripts/sync-cloud-validations.sh @@ -27,25 +27,20 @@ sync_cloud_validations() { # Create output directory if it doesn't exist mkdir -p "$OUTPUT_FOLDER" - # Download validations with headers - echo "Downloading validations..." - curl -s -D /tmp/validations_headers "$VALIDATION_BASE/cypress-app/validations" > "$JS_FILE" - + # Download types only (safer than downloading executable .js schemas) echo "Downloading types..." curl -s -D /tmp/types_headers "$VALIDATION_BASE/cypress-app/validations/types" > "$DTS_FILE" + # TODO: Download .js validations when cloud package publishes an npm SDK + # For now, we only download TypeScript definitions for type safety + # echo "Downloading validations..." + # curl -s -D /tmp/validations_headers "$VALIDATION_BASE/cypress-app/validations" > "$JS_FILE" + # Extract ETag headers - VALIDATIONS_ETAG=$(grep -i "etag:" /tmp/validations_headers | cut -d' ' -f2 | tr -d '\r\n') + # VALIDATIONS_ETAG=$(grep -i "etag:" /tmp/validations_headers | cut -d' ' -f2 | tr -d '\r\n') TYPES_ETAG=$(grep -i "etag:" /tmp/types_headers | cut -d' ' -f2 | tr -d '\r\n') - # Add ETag as comment to the files - { - echo "// ETag: $VALIDATIONS_ETAG" - echo "// Last-Synced: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" - echo "" - cat "$JS_FILE" - } > "$JS_FILE.tmp" && mv "$JS_FILE.tmp" "$JS_FILE" - + # Add ETag as comment to the types file { echo "// ETag: $TYPES_ETAG" echo "// Last-Synced: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" @@ -54,14 +49,14 @@ sync_cloud_validations() { } > "$DTS_FILE.tmp" && mv "$DTS_FILE.tmp" "$DTS_FILE" # Clean up temp files - rm -f /tmp/validations_headers /tmp/types_headers + rm -f /tmp/types_headers echo "✅ Cloud validations synced successfully" } ensure_cloud_validations() { - if [[ ! -f "$JS_FILE" || ! -f "$DTS_FILE" ]]; then - echo "Cloud validation files missing, syncing..." + if [[ ! -f "$DTS_FILE" ]]; then + echo "Cloud validation types file missing, syncing..." if ! sync_cloud_validations; then echo "❌ Failed to sync cloud validations. Build may fail without these files." exit 1 @@ -69,31 +64,29 @@ ensure_cloud_validations() { return fi - # Extract stored ETags from the files - STORED_JS_ETAG=$(head -n 1 "$JS_FILE" | sed 's|// ETag: ||' | tr -d '\r\n') + # Extract stored ETag from the types file STORED_DTS_ETAG=$(head -n 1 "$DTS_FILE" | sed 's|// ETag: ||' | tr -d '\r\n') echo "Checking if cloud validations are up to date..." - # Get current ETags without downloading the full content - # If we can't fetch ETags (offline), just use existing files - CURRENT_JS_ETAG=$(curl -s -I "$VALIDATION_BASE/cypress-app/validations" 2>/dev/null | grep -i "etag:" | cut -d' ' -f2 | tr -d '\r\n') + # Get current ETag without downloading the full content + # If we can't fetch ETag (offline), just use existing file CURRENT_DTS_ETAG=$(curl -s -I "$VALIDATION_BASE/cypress-app/validations/types" 2>/dev/null | grep -i "etag:" | cut -d' ' -f2 | tr -d '\r\n') - # If we couldn't fetch ETags (offline), use existing files - if [[ -z "$CURRENT_JS_ETAG" || -z "$CURRENT_DTS_ETAG" ]]; then - echo "⚠️ Could not check ETags (offline?), using existing files" + # If we couldn't fetch ETag (offline), use existing file + if [[ -z "$CURRENT_DTS_ETAG" ]]; then + echo "⚠️ Could not check ETag (offline?), using existing file" return fi # Compare ETags - if [[ "$STORED_JS_ETAG" != "$CURRENT_JS_ETAG" || "$STORED_DTS_ETAG" != "$CURRENT_DTS_ETAG" ]]; then - echo "Cloud validation files are outdated (ETags changed), syncing..." + if [[ "$STORED_DTS_ETAG" != "$CURRENT_DTS_ETAG" ]]; then + echo "Cloud validation types are outdated (ETag changed), syncing..." if ! sync_cloud_validations; then - echo "⚠️ Failed to sync, but existing files will be used" + echo "⚠️ Failed to sync, but existing file will be used" fi else - echo "✅ Cloud validation files are up to date (ETags match)" + echo "✅ Cloud validation types are up to date (ETag matches)" fi } From b4fe99bea6e6d3f0535329cafe511c23d4f1b1ae Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Thu, 2 Oct 2025 12:46:43 -0400 Subject: [PATCH 04/14] fix logic error --- packages/server/lib/cloud/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/lib/cloud/api/index.ts b/packages/server/lib/cloud/api/index.ts index f8100695875..25bd35c35a7 100644 --- a/packages/server/lib/cloud/api/index.ts +++ b/packages/server/lib/cloud/api/index.ts @@ -425,7 +425,7 @@ export default { } } - if (script && options.testingType === 'e2e' || options.testingType === 'component') { + if (script && (options.testingType === 'e2e' || options.testingType === 'component')) { const config = options.project.getConfig() await options.project.protocolManager.prepareAndSetupProtocol(script, { From f0e7345ceb2471231723a98c244e27557662db21 Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Thu, 2 Oct 2025 12:49:53 -0400 Subject: [PATCH 05/14] additional pre-scripts --- packages/server/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 53251da55fd..58aaa87d05f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -4,8 +4,8 @@ "private": true, "main": "index.js", "scripts": { - "build-prod": "tsc || echo 'built, with type errors'", - "check-ts": "tsc --noEmit", + "build-prod": "yarn ensure-cloud-validations && tsc || echo 'built, with type errors'", + "check-ts": "yarn ensure-cloud-validations && tsc --noEmit", "clean-deps": "rimraf node_modules", "codecov": "codecov", "dev": "node index.js", From 753cee90be3396abeff8f6ac4e489bb31d4aa3db Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Thu, 2 Oct 2025 12:57:49 -0400 Subject: [PATCH 06/14] consolidate zod versions --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index f32b51e48b6..772705345ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34470,7 +34470,7 @@ zod@3.25.75: resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.75.tgz#8ff9be2fbbcb381a9236f9f74a8879ca29dcc504" integrity sha512-OhpzAmVzabPOL6C3A3gpAifqr9MqihV/Msx3gor2b2kviCgcb+HM9SEOpMWwwNp9MRunWnhtAKUoo0AHhjyPPg== -zod@^3.22.5, zod@^3.23.8, zod@^3.24.2: +zod@^3.22.5, zod@^3.23.8: version "3.25.76" resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== From 36318c25926c75235a1d39ed41187824366f3993 Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Thu, 2 Oct 2025 12:57:49 -0400 Subject: [PATCH 07/14] consolidate zod versions --- packages/server/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/package.json b/packages/server/package.json index 58aaa87d05f..c05810142a1 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -214,7 +214,7 @@ "webpack": "^5.88.2", "ws": "5.2.4", "xvfb-maybe": "0.2.1", - "zod": "^3.24.2" + "zod": "^3.23.8" }, "files": [ "config", From b14d51f439a17fe65d036dff25efcc8295b2d85e Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Thu, 2 Oct 2025 14:51:17 -0400 Subject: [PATCH 08/14] fix logic regarding post instance tests responses --- packages/server/lib/modes/record.ts | 78 +++++++++++++---------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/packages/server/lib/modes/record.ts b/packages/server/lib/modes/record.ts index 88fe28be0fa..3ef6fdcde81 100644 --- a/packages/server/lib/modes/record.ts +++ b/packages/server/lib/modes/record.ts @@ -532,7 +532,7 @@ async function createInstance (options: InstanceOptions) { } } -const _postInstanceTests = ({ +async function _postInstanceTests ({ runId, instanceId, config, @@ -541,17 +541,18 @@ const _postInstanceTests = ({ parallel, ciBuildId, group, -}) => { - return api.postInstanceTests({ - runId, - instanceId, - config, - tests, - hooks, - }) - .catch((err: any) => { - throwCloudCannotProceed({ parallel, ciBuildId, group, err }) - }) +}) { + try { + return await api.postInstanceTests({ + runId, + instanceId, + config, + tests, + hooks, + }) + } catch (err: unknown) { + throw cloudCannotProceedErr({ parallel, ciBuildId, group, err }) + } } const createRunAndRecordSpecs = (options: any = {}) => { @@ -774,42 +775,33 @@ const createRunAndRecordSpecs = (options: any = {}) => { }) .value() - const responseDidFail = {} - const response = await _postInstanceTests({ - runId, - instanceId, - config: resolvedRuntimeConfig, - tests, - hooks, - parallel, - ciBuildId, - group, - }) - .catch((err: any) => { - onError(err) - - return responseDidFail - }) - - if (response === responseDidFail) { - debug('`responseDidFail` equals `response`, allowing browser to hang until it is killed: Response %o', { responseDidFail }) + try { + const response = await _postInstanceTests({ + runId, + instanceId, + config: resolvedRuntimeConfig, + tests, + hooks, + parallel, + ciBuildId, + group, + }) - // dont call the cb, let the browser hang until it's killed - return - } + if (_.some(response.actions, { type: 'SPEC', action: 'SKIP' })) { + errorsWarning('CLOUD_CANCEL_SKIPPED_SPEC') - if (_.some(response.actions, { type: 'SPEC', action: 'SKIP' })) { - errorsWarning('CLOUD_CANCEL_SKIPPED_SPEC') + // set a property on the response so the browser runner + // knows not to start executing tests + project.emit('end', { skippedSpec: true, stats: {} }) - // set a property on the response so the browser runner - // knows not to start executing tests - project.emit('end', { skippedSpec: true, stats: {} }) + // dont call the cb, let the browser hang until it's killed + return + } - // dont call the cb, let the browser hang until it's killed - return + return cb(response) + } catch (err: unknown) { + debug('postInstanceTests failed, allowing browser to hang until it is killed: Error %o', { err }) } - - return cb(response) }) return runAllSpecs({ From 331519cf862ea6b9bb39aa3376eaee4cba4e99b0 Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Tue, 7 Oct 2025 12:40:04 -0400 Subject: [PATCH 09/14] Update record.ts - add onError back to postInstanceTests --- packages/server/lib/modes/record.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server/lib/modes/record.ts b/packages/server/lib/modes/record.ts index 3ef6fdcde81..e5a81cc6fc5 100644 --- a/packages/server/lib/modes/record.ts +++ b/packages/server/lib/modes/record.ts @@ -800,6 +800,7 @@ const createRunAndRecordSpecs = (options: any = {}) => { return cb(response) } catch (err: unknown) { + onError(err) debug('postInstanceTests failed, allowing browser to hang until it is killed: Error %o', { err }) } }) From e108babad653e0d98a39fd026898b9dcdbc12b60 Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Fri, 10 Oct 2025 14:55:59 -0400 Subject: [PATCH 10/14] lint --- packages/server/lib/cloud/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/lib/cloud/api/index.ts b/packages/server/lib/cloud/api/index.ts index 4c6566a6f0d..fb48f3a1a54 100644 --- a/packages/server/lib/cloud/api/index.ts +++ b/packages/server/lib/cloud/api/index.ts @@ -659,7 +659,7 @@ export default { return result }) }, - + async getCaptureProtocolScript (url: string, options: { displayRetryErrors?: boolean } = { displayRetryErrors: true }) { // TODO(protocol): Ensure this is removed in production if (process.env.CYPRESS_LOCAL_PROTOCOL_PATH) { From 0ffa7596376c50899b4ebf2e2dbba8d2deefe6c5 Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Tue, 14 Oct 2025 11:33:58 -0400 Subject: [PATCH 11/14] add packages/server as an implicit dep to v8-snapshot tooling --- tooling/v8-snapshot/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tooling/v8-snapshot/package.json b/tooling/v8-snapshot/package.json index 45cd8c7ffac..838f382520b 100644 --- a/tooling/v8-snapshot/package.json +++ b/tooling/v8-snapshot/package.json @@ -58,7 +58,8 @@ }, "nx": { "implicitDependencies": [ - "@packages/data-context" + "@packages/data-context", + "@packages/server" ] } } From 65256e448697a6353860f9643ce0c042d8a40392 Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Tue, 14 Oct 2025 13:54:28 -0400 Subject: [PATCH 12/14] fetch cloud validations before @tooling/v8-snapshot build --- packages/server/lib/cloud/user.ts | 6 ++++-- tooling/v8-snapshot/package.json | 12 +++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/server/lib/cloud/user.ts b/packages/server/lib/cloud/user.ts index 11fa3cc7484..ccda5b6bc93 100644 --- a/packages/server/lib/cloud/user.ts +++ b/packages/server/lib/cloud/user.ts @@ -13,8 +13,10 @@ export = { return cache.setUser(user) }, - getBaseLoginUrl (): string { - return api.getAuthUrls().get('dashboardAuthUrl') + async getBaseLoginUrl (): Promise { + const res = await api.getAuthUrls() + + return res!.dashboardAuthUrl }, logOut () { diff --git a/tooling/v8-snapshot/package.json b/tooling/v8-snapshot/package.json index 838f382520b..a56aefa359f 100644 --- a/tooling/v8-snapshot/package.json +++ b/tooling/v8-snapshot/package.json @@ -58,8 +58,14 @@ }, "nx": { "implicitDependencies": [ - "@packages/data-context", - "@packages/server" - ] + "@packages/data-context" + ], + "targets": { + "build": { + "dependsOn": [ + "@packages/server:ensure-cloud-validations" + ] + } + } } } From cb8b59f0c7dd8a0af84af5e25dc4a12be2b35e6e Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Tue, 14 Oct 2025 14:33:38 -0400 Subject: [PATCH 13/14] run specific data-context targets to prevent circular dependency --- tooling/v8-snapshot/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tooling/v8-snapshot/package.json b/tooling/v8-snapshot/package.json index a56aefa359f..42fdd0be8d1 100644 --- a/tooling/v8-snapshot/package.json +++ b/tooling/v8-snapshot/package.json @@ -63,7 +63,10 @@ "targets": { "build": { "dependsOn": [ - "@packages/server:ensure-cloud-validations" + "@packages/server:ensure-cloud-validations", + "@packages/data-context:build:graphql", + "@packages/data-context:build:schema", + "@packages/data-context:nexus-build" ] } } From c537692fca5703a2989b43021693c65e7ea8472d Mon Sep 17 00:00:00 2001 From: Cacie Prins Date: Tue, 14 Oct 2025 14:50:47 -0400 Subject: [PATCH 14/14] manually build server typedefs @@ --- tooling/v8-snapshot/package.json | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/tooling/v8-snapshot/package.json b/tooling/v8-snapshot/package.json index 42fdd0be8d1..af4d0c56d40 100644 --- a/tooling/v8-snapshot/package.json +++ b/tooling/v8-snapshot/package.json @@ -5,10 +5,11 @@ "private": true, "main": "dist/v8-snapshot.js", "scripts": { - "build": "tsc && (rimraf ./dist/blueprint && cpr ./src/blueprint ./dist/blueprint)", + "build": "yarn ensure-typedefs && tsc && (rimraf ./dist/blueprint && cpr ./src/blueprint ./dist/blueprint)", "check-ts": "tsc --noEmit", "clean": "rimraf dist", "clean-deps": "rimraf node_modules", + "ensure-typedefs": "cd ../../packages/server && yarn ensure-cloud-validations", "test": "yarn test-unit", "test-integration": "mocha test/integration/**/*.spec.ts --config ./test/.mocharc.js", "test-unit": "mocha test/unit/**/*.spec.ts --config ./test/.mocharc.js", @@ -59,16 +60,6 @@ "nx": { "implicitDependencies": [ "@packages/data-context" - ], - "targets": { - "build": { - "dependsOn": [ - "@packages/server:ensure-cloud-validations", - "@packages/data-context:build:graphql", - "@packages/data-context:build:schema", - "@packages/data-context:nexus-build" - ] - } - } + ] } }