From 47e7b0087a81a8eaddffc35ddb55ffc2dee12749 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Fri, 31 Jul 2026 09:52:40 -0400 Subject: [PATCH 1/2] data-connect-api-client-internal.ts: add "x-firebase-sqlconnect-affinity" header --- src/data-connect/data-connect-api-client-internal.ts | 6 ++++-- .../data-connect/data-connect-api-client-internal.spec.ts | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/data-connect/data-connect-api-client-internal.ts b/src/data-connect/data-connect-api-client-internal.ts index b200eb120e..54dcee6f1e 100644 --- a/src/data-connect/data-connect-api-client-internal.ts +++ b/src/data-connect/data-connect-api-client-internal.ts @@ -70,11 +70,12 @@ const IMPERSONATE_MUTATION_ENDPOINT = 'impersonateMutation'; /** @internal The maximum number of items allowed in the @allow directive's maxCount argument. */ export const ALLOW_DIRECTIVE_MAX_COUNT = 10_000; -function getHeaders(isUsingGen: boolean): { [key: string]: string } { +function getHeaders(projectId: string, serviceId: string, isUsingGen: boolean): { [key: string]: string } { const headerValue = { 'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`, 'X-Goog-Api-Client': utils.getMetricsHeader(), 'X-Client-Version': `node/${utils.getSdkVersion()}`, + 'X-Firebase-Sqlconnect-Affinity': `${projectId}${serviceId}`, }; if (isUsingGen) { headerValue['X-Goog-Api-Client'] += ' admin-js/gen'; @@ -386,10 +387,11 @@ export class DataConnectApiClient { */ private async makeGqlRequest(url: string, data: object): Promise> { + const projectId = await this.getProjectId(); const request: HttpRequestConfig = { method: 'POST', url, - headers: getHeaders(this.isUsingGen), + headers: getHeaders(projectId, this.connectorConfig.serviceId, this.isUsingGen), data, }; const resp = await this.httpClient.send(request); diff --git a/test/unit/data-connect/data-connect-api-client-internal.spec.ts b/test/unit/data-connect/data-connect-api-client-internal.spec.ts index cfc51e5b38..eb9b7d111c 100644 --- a/test/unit/data-connect/data-connect-api-client-internal.spec.ts +++ b/test/unit/data-connect/data-connect-api-client-internal.spec.ts @@ -54,6 +54,7 @@ describe('DataConnectApiClient', () => { 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader(), 'X-Client-Version': `node/${getSdkVersion()}`, + 'X-Firebase-Sqlconnect-Affinity': 'test-projectmy-service', }; const EXPECTED_HEADERS_WITH_GEN = { @@ -61,6 +62,7 @@ describe('DataConnectApiClient', () => { 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader() + ' admin-js/gen', 'X-Client-Version': `node/${getSdkVersion()}`, + 'X-Firebase-Sqlconnect-Affinity': 'test-projectmy-service', }; const EMULATOR_EXPECTED_HEADERS = { @@ -68,6 +70,7 @@ describe('DataConnectApiClient', () => { 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader(), 'X-Client-Version': `node/${getSdkVersion()}`, + 'X-Firebase-Sqlconnect-Affinity': 'test-projectmy-service', }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service ' From 99549fa7a07a823b09c8b202afe3664aa32e5977 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Fri, 31 Jul 2026 10:09:59 -0400 Subject: [PATCH 2/2] data-connect-api-client-internal.ts: GetHeadersParameters added, to reduce the chance that the caller will invert the two string arguments. --- .../data-connect-api-client-internal.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/data-connect/data-connect-api-client-internal.ts b/src/data-connect/data-connect-api-client-internal.ts index 54dcee6f1e..89f863b5e4 100644 --- a/src/data-connect/data-connect-api-client-internal.ts +++ b/src/data-connect/data-connect-api-client-internal.ts @@ -70,7 +70,14 @@ const IMPERSONATE_MUTATION_ENDPOINT = 'impersonateMutation'; /** @internal The maximum number of items allowed in the @allow directive's maxCount argument. */ export const ALLOW_DIRECTIVE_MAX_COUNT = 10_000; -function getHeaders(projectId: string, serviceId: string, isUsingGen: boolean): { [key: string]: string } { +interface GetHeadersParameters { + projectId: string; + serviceId: string; + isUsingGen: boolean; +} + +function getHeaders(parameters: GetHeadersParameters): { [key: string]: string } { + const { projectId, serviceId, isUsingGen } = parameters; const headerValue = { 'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`, 'X-Goog-Api-Client': utils.getMetricsHeader(), @@ -391,7 +398,11 @@ export class DataConnectApiClient { const request: HttpRequestConfig = { method: 'POST', url, - headers: getHeaders(projectId, this.connectorConfig.serviceId, this.isUsingGen), + headers: getHeaders({ + projectId, + serviceId: this.connectorConfig.serviceId, + isUsingGen: this.isUsingGen, + }), data, }; const resp = await this.httpClient.send(request);