From b91d42d53e3eb8117449345f1e3fee33f8d597de Mon Sep 17 00:00:00 2001 From: Wanda Mora Date: Tue, 12 May 2026 22:51:59 +0000 Subject: [PATCH 1/4] refactor: clean up type casting in region resolution --- src/deploy/functions/prepare.ts | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/deploy/functions/prepare.ts b/src/deploy/functions/prepare.ts index de5278dc96e..fa0d36aee29 100644 --- a/src/deploy/functions/prepare.ts +++ b/src/deploy/functions/prepare.ts @@ -66,6 +66,22 @@ import * as prompt from "../../prompt"; export const EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE"; export const DEFAULT_FUNCTION_REGION = "us-central1"; +interface EventTriggerResolutionTarget { + project: string; + eventTrigger: { + eventType: string; + eventFilters?: Record>; + region?: string | build.Expression; + }; +} + +interface BlockingTriggerResolutionTarget { + blockingTrigger: { + eventType: string; + options?: Record; + }; +} + /** * Prepare functions codebases for deploy. */ @@ -381,11 +397,10 @@ export async function resolveDefaultRegionsForBuild( } else { // Match triggers. try { - const fullEndpoint = { ...endpoint, id } as any; if (build.isBlockingTriggered(endpoint)) { - resolvedRegion = resolveRegionForBlockingTrigger(fullEndpoint); + resolvedRegion = resolveRegionForBlockingTrigger(endpoint); } else if (build.isEventTriggered(endpoint)) { - resolvedRegion = await resolveRegionForEventTrigger(fullEndpoint); + resolvedRegion = await resolveRegionForEventTrigger(endpoint); } } catch (err: any) { logger.debug( @@ -400,15 +415,13 @@ export async function resolveDefaultRegionsForBuild( } } -function resolveRegionForBlockingTrigger( - endpoint: backend.Endpoint & backend.BlockingTriggered, -): string { +function resolveRegionForBlockingTrigger(endpoint: BlockingTriggerResolutionTarget): string { const eventType = endpoint.blockingTrigger.eventType; if ((events.AUTH_BLOCKING_EVENTS as readonly string[]).includes(eventType)) { return "us-east1"; } - if (isGlobalAILogicEndpoint(endpoint)) { + if (isGlobalAILogicEndpoint(endpoint as backend.Endpoint)) { return "us-east1"; } @@ -416,7 +429,7 @@ function resolveRegionForBlockingTrigger( } async function resolveRegionForEventTrigger( - endpoint: backend.Endpoint & backend.EventTriggered, + endpoint: EventTriggerResolutionTarget, ): Promise { const eventTrigger = endpoint.eventTrigger; const eventType = eventTrigger.eventType; From b617205b25b384a651b95c7d662bcf4f29765953 Mon Sep 17 00:00:00 2001 From: Wanda Mora Date: Tue, 12 May 2026 23:21:53 +0000 Subject: [PATCH 2/4] Consolidate interface and refactor AILogic checks --- src/deploy/functions/prepare.ts | 26 ++++++++++++++---------- src/deploy/functions/services/ailogic.ts | 26 ++++++++++++++++++++---- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/deploy/functions/prepare.ts b/src/deploy/functions/prepare.ts index fa0d36aee29..03f8428f833 100644 --- a/src/deploy/functions/prepare.ts +++ b/src/deploy/functions/prepare.ts @@ -66,17 +66,17 @@ import * as prompt from "../../prompt"; export const EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE"; export const DEFAULT_FUNCTION_REGION = "us-central1"; -interface EventTriggerResolutionTarget { +/** + * A subset of the backend.Endpoint interface for the purposes of resolving regions. + */ +interface TriggerResolutionTarget { project: string; - eventTrigger: { + eventTrigger?: { eventType: string; eventFilters?: Record>; region?: string | build.Expression; }; -} - -interface BlockingTriggerResolutionTarget { - blockingTrigger: { + blockingTrigger?: { eventType: string; options?: Record; }; @@ -415,22 +415,26 @@ export async function resolveDefaultRegionsForBuild( } } -function resolveRegionForBlockingTrigger(endpoint: BlockingTriggerResolutionTarget): string { +function resolveRegionForBlockingTrigger(endpoint: TriggerResolutionTarget): string { + if (!endpoint.blockingTrigger) { + return DEFAULT_FUNCTION_REGION; + } const eventType = endpoint.blockingTrigger.eventType; if ((events.AUTH_BLOCKING_EVENTS as readonly string[]).includes(eventType)) { return "us-east1"; } - if (isGlobalAILogicEndpoint(endpoint as backend.Endpoint)) { + if (isGlobalAILogicEndpoint(endpoint)) { return "us-east1"; } return DEFAULT_FUNCTION_REGION; } -async function resolveRegionForEventTrigger( - endpoint: EventTriggerResolutionTarget, -): Promise { +async function resolveRegionForEventTrigger(endpoint: TriggerResolutionTarget): Promise { + if (!endpoint.eventTrigger) { + return DEFAULT_FUNCTION_REGION; + } const eventTrigger = endpoint.eventTrigger; const eventType = eventTrigger.eventType; diff --git a/src/deploy/functions/services/ailogic.ts b/src/deploy/functions/services/ailogic.ts index b785d4f2e43..80a6d431941 100644 --- a/src/deploy/functions/services/ailogic.ts +++ b/src/deploy/functions/services/ailogic.ts @@ -15,7 +15,15 @@ export const AI_LOGIC_EVENTS = [ AI_LOGIC_AFTER_GENERATE_CONTENT, ] as const; -export type AILogicEndpoint = backend.Endpoint & { +export interface AILogicTriggerTarget { + blockingTrigger?: { + eventType: string; + options?: Record; + }; + project?: string; +} + +export type AILogicTrigger = { blockingTrigger: { eventType: (typeof AI_LOGIC_EVENTS)[number]; options?: { @@ -24,8 +32,15 @@ export type AILogicEndpoint = backend.Endpoint & { }; }; -export function isAILogicEvent(endpoint: backend.Endpoint): endpoint is AILogicEndpoint { - if (!backend.isBlockingTriggered(endpoint)) { +export type AILogicEndpoint = backend.Endpoint & AILogicTrigger; + +/** + * Type guard to check if a trigger target is an AI Logic event trigger. + */ +export function isAILogicEvent( + endpoint: T, +): endpoint is T & AILogicTrigger { + if (!endpoint.blockingTrigger) { return false; } return AI_LOGIC_EVENTS.includes( @@ -33,7 +48,10 @@ export function isAILogicEvent(endpoint: backend.Endpoint): endpoint is AILogicE ); } -export function isGlobalAILogicEndpoint(endpoint: backend.Endpoint): boolean { +/** + * Check if an AI Logic trigger target is global (i.e. not a regional webhook). + */ +export function isGlobalAILogicEndpoint(endpoint: AILogicTriggerTarget): boolean { if (!isAILogicEvent(endpoint)) { return false; } From cd7e85a6053ed803bd2a5cd92aa6ac23a0ad3c8c Mon Sep 17 00:00:00 2001 From: Wanda Mora Date: Tue, 19 May 2026 17:13:55 +0000 Subject: [PATCH 3/4] Replace interface for individual args --- src/deploy/functions/prepare.ts | 47 ++++++++---------------- src/deploy/functions/services/ailogic.ts | 31 ++++++++-------- 2 files changed, 30 insertions(+), 48 deletions(-) diff --git a/src/deploy/functions/prepare.ts b/src/deploy/functions/prepare.ts index 03f8428f833..e24ade946e7 100644 --- a/src/deploy/functions/prepare.ts +++ b/src/deploy/functions/prepare.ts @@ -16,7 +16,7 @@ import * as events from "../../functions/events/v1"; import { getDatabase } from "./services/firestore"; import { getBucket } from "./services/storage"; import { getDatabaseInstanceDetails } from "./services/database"; -import { isGlobalAILogicEndpoint } from "./services/ailogic"; +import { isGlobalAILogicTrigger } from "./services/ailogic"; import { parseServiceName, parseConnectorName } from "../../dataconnect/names"; import { functionsOrigin, @@ -66,22 +66,6 @@ import * as prompt from "../../prompt"; export const EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE"; export const DEFAULT_FUNCTION_REGION = "us-central1"; -/** - * A subset of the backend.Endpoint interface for the purposes of resolving regions. - */ -interface TriggerResolutionTarget { - project: string; - eventTrigger?: { - eventType: string; - eventFilters?: Record>; - region?: string | build.Expression; - }; - blockingTrigger?: { - eventType: string; - options?: Record; - }; -} - /** * Prepare functions codebases for deploy. */ @@ -398,9 +382,12 @@ export async function resolveDefaultRegionsForBuild( // Match triggers. try { if (build.isBlockingTriggered(endpoint)) { - resolvedRegion = resolveRegionForBlockingTrigger(endpoint); + resolvedRegion = resolveRegionForBlockingTrigger(endpoint.blockingTrigger); } else if (build.isEventTriggered(endpoint)) { - resolvedRegion = await resolveRegionForEventTrigger(endpoint); + resolvedRegion = await resolveRegionForEventTrigger( + endpoint.project, + endpoint.eventTrigger, + ); } } catch (err: any) { logger.debug( @@ -415,27 +402,23 @@ export async function resolveDefaultRegionsForBuild( } } -function resolveRegionForBlockingTrigger(endpoint: TriggerResolutionTarget): string { - if (!endpoint.blockingTrigger) { - return DEFAULT_FUNCTION_REGION; - } - const eventType = endpoint.blockingTrigger.eventType; +function resolveRegionForBlockingTrigger(blockingTrigger: build.BlockingTrigger): string { + const eventType = blockingTrigger.eventType; if ((events.AUTH_BLOCKING_EVENTS as readonly string[]).includes(eventType)) { return "us-east1"; } - if (isGlobalAILogicEndpoint(endpoint)) { + if (isGlobalAILogicTrigger(blockingTrigger)) { return "us-east1"; } return DEFAULT_FUNCTION_REGION; } -async function resolveRegionForEventTrigger(endpoint: TriggerResolutionTarget): Promise { - if (!endpoint.eventTrigger) { - return DEFAULT_FUNCTION_REGION; - } - const eventTrigger = endpoint.eventTrigger; +async function resolveRegionForEventTrigger( + project: string, + eventTrigger: build.EventTrigger, +): Promise { const eventType = eventTrigger.eventType; // Global functions should be deployed to us-east1. @@ -458,7 +441,7 @@ async function resolveRegionForEventTrigger(endpoint: TriggerResolutionTarget): if (eventType.startsWith("google.cloud.firestore.")) { try { const databaseId = eventTrigger.eventFilters?.database || "(default)"; - const db = await getDatabase(endpoint.project, databaseId); + const db = await getDatabase(project, databaseId); const locationId = db.locationId.toLowerCase(); if (locationId === "nam5" || locationId === "nam7") return "us-central1"; @@ -498,7 +481,7 @@ async function resolveRegionForEventTrigger(endpoint: TriggerResolutionTarget): try { const instanceName = eventTrigger.eventFilters?.instance; if (instanceName) { - const details = await getDatabaseInstanceDetails(endpoint.project, instanceName); + const details = await getDatabaseInstanceDetails(project, instanceName); if (details.location && details.location !== "-") { return details.location.toLowerCase(); } diff --git a/src/deploy/functions/services/ailogic.ts b/src/deploy/functions/services/ailogic.ts index 80a6d431941..67046f3185e 100644 --- a/src/deploy/functions/services/ailogic.ts +++ b/src/deploy/functions/services/ailogic.ts @@ -1,4 +1,5 @@ import * as backend from "../backend"; +import * as build from "../build"; import { FirebaseError, getErrStatus } from "../../../error"; import { Name, Service } from "./index"; import * as ailogicApi from "../../../gcp/ailogic"; @@ -15,15 +16,7 @@ export const AI_LOGIC_EVENTS = [ AI_LOGIC_AFTER_GENERATE_CONTENT, ] as const; -export interface AILogicTriggerTarget { - blockingTrigger?: { - eventType: string; - options?: Record; - }; - project?: string; -} - -export type AILogicTrigger = { +export type AILogicEndpoint = backend.Endpoint & { blockingTrigger: { eventType: (typeof AI_LOGIC_EVENTS)[number]; options?: { @@ -32,15 +25,11 @@ export type AILogicTrigger = { }; }; -export type AILogicEndpoint = backend.Endpoint & AILogicTrigger; - /** * Type guard to check if a trigger target is an AI Logic event trigger. */ -export function isAILogicEvent( - endpoint: T, -): endpoint is T & AILogicTrigger { - if (!endpoint.blockingTrigger) { +export function isAILogicEvent(endpoint: backend.Endpoint): endpoint is AILogicEndpoint { + if (!backend.isBlockingTriggered(endpoint)) { return false; } return AI_LOGIC_EVENTS.includes( @@ -48,10 +37,20 @@ export function isAILogicEvent( ); } +/** + * Check if a blocking trigger is a global AI Logic trigger (not a regional webhook). + */ +export function isGlobalAILogicTrigger(blockingTrigger: build.BlockingTrigger): boolean { + return ( + AI_LOGIC_EVENTS.includes(blockingTrigger.eventType as any) && + !blockingTrigger.options?.regionalWebhook + ); +} + /** * Check if an AI Logic trigger target is global (i.e. not a regional webhook). */ -export function isGlobalAILogicEndpoint(endpoint: AILogicTriggerTarget): boolean { +export function isGlobalAILogicEndpoint(endpoint: backend.Endpoint): boolean { if (!isAILogicEvent(endpoint)) { return false; } From 983a0fbe3d874c168027dcbffeb4586c4b527981 Mon Sep 17 00:00:00 2001 From: Wanda Mora Date: Tue, 19 May 2026 17:22:17 +0000 Subject: [PATCH 4/4] Cleanup ailogic file --- src/deploy/functions/services/ailogic.ts | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/deploy/functions/services/ailogic.ts b/src/deploy/functions/services/ailogic.ts index 67046f3185e..f3987a13f67 100644 --- a/src/deploy/functions/services/ailogic.ts +++ b/src/deploy/functions/services/ailogic.ts @@ -25,9 +25,6 @@ export type AILogicEndpoint = backend.Endpoint & { }; }; -/** - * Type guard to check if a trigger target is an AI Logic event trigger. - */ export function isAILogicEvent(endpoint: backend.Endpoint): endpoint is AILogicEndpoint { if (!backend.isBlockingTriggered(endpoint)) { return false; @@ -42,21 +39,11 @@ export function isAILogicEvent(endpoint: backend.Endpoint): endpoint is AILogicE */ export function isGlobalAILogicTrigger(blockingTrigger: build.BlockingTrigger): boolean { return ( - AI_LOGIC_EVENTS.includes(blockingTrigger.eventType as any) && + AI_LOGIC_EVENTS.includes(blockingTrigger.eventType as (typeof AI_LOGIC_EVENTS)[number]) && !blockingTrigger.options?.regionalWebhook ); } -/** - * Check if an AI Logic trigger target is global (i.e. not a regional webhook). - */ -export function isGlobalAILogicEndpoint(endpoint: backend.Endpoint): boolean { - if (!isAILogicEvent(endpoint)) { - return false; - } - return !endpoint.blockingTrigger.options?.regionalWebhook; -} - export class AILogicService implements Service { name: Name; api: string;