diff --git a/src/experiments.ts b/src/experiments.ts index 87168a1f716..909a9a89425 100644 --- a/src/experiments.ts +++ b/src/experiments.ts @@ -193,6 +193,11 @@ export const ALL_EXPERIMENTS = experiments({ default: true, public: false, }, + fdcrealtime: { + shortDescription: "Enable Firebase Data Connect realtime feature.", + default: false, + public: false, + }, }); export type ExperimentName = keyof typeof ALL_EXPERIMENTS; diff --git a/src/init/features/dataconnect/sdk.spec.ts b/src/init/features/dataconnect/sdk.spec.ts index 7c5365fa5c1..17e428614e9 100644 --- a/src/init/features/dataconnect/sdk.spec.ts +++ b/src/init/features/dataconnect/sdk.spec.ts @@ -23,6 +23,7 @@ import * as fsutils from "../../../fsutils"; import * as auth from "../../../auth"; import * as utils from "../../../utils"; import * as prompt from "../../../prompt"; +import * as experiments from "../../../experiments"; const expect = chai.expect; @@ -49,6 +50,10 @@ describe("addSdkGenerateToConnectorYaml", () => { }; }); + afterEach(() => { + sinon.restore(); + }); + it("should add javascriptSdk for web platform", () => { addSdkGenerateToConnectorYaml(connectorInfo, connectorYaml, app); expect(connectorYaml.generate?.javascriptSdk).to.deep.equal([ @@ -120,6 +125,35 @@ describe("addSdkGenerateToConnectorYaml", () => { }, ]); }); + + it("should conditionally inject clientCache if fdcrealtime is enabled", () => { + sinon.stub(experiments, "isEnabled").withArgs("fdcrealtime").returns(true); + addSdkGenerateToConnectorYaml(connectorInfo, connectorYaml, app); + expect((connectorYaml.generate?.javascriptSdk as any)[0].clientCache).to.deep.equal({}); + }); + + it("should NOT overwrite existing clientCache configuration", () => { + sinon.stub(experiments, "isEnabled").withArgs("fdcrealtime").returns(true); + connectorYaml.generate = { + javascriptSdk: [ + { + outputDir: "../app/src/dataconnect-generated", + package: "@dataconnect/generated", + packageJsonDir: "../app", + react: false, + angular: false, + clientCache: { + type: "memory", + } as any, + }, + ], + }; + addSdkGenerateToConnectorYaml(connectorInfo, connectorYaml, app); + expect(connectorYaml.generate?.javascriptSdk).to.have.lengthOf(1); + expect((connectorYaml.generate?.javascriptSdk as any)[0].clientCache).to.deep.equal({ + type: "memory", + }); + }); }); describe("chooseApp", () => { diff --git a/src/init/features/dataconnect/sdk.ts b/src/init/features/dataconnect/sdk.ts index 5eba5e07aaf..8f98b8b6725 100644 --- a/src/init/features/dataconnect/sdk.ts +++ b/src/init/features/dataconnect/sdk.ts @@ -15,7 +15,9 @@ import { DartSDK, JavascriptSDK, KotlinSDK, + SwiftSDK, } from "../../../dataconnect/types"; +import * as experiments from "../../../experiments"; import { FirebaseError } from "../../../error"; import { isArray } from "lodash"; import { @@ -381,19 +383,23 @@ export function addSdkGenerateToConnectorYaml( case Platform.WEB: { const javascriptSdk: JavascriptSDK = { - outputDir: path.relative(connectorDir, path.join(appDir, `src/dataconnect-generated`)), - package: `@dataconnect/generated`, - packageJsonDir: path.relative(connectorDir, appDir), - react: false, - angular: false, + outputDir: path.relative( + connectorDir, + path.join(app.directory, "src/dataconnect-generated"), + ), + package: "@dataconnect/generated", + packageJsonDir: path.relative(connectorDir, app.directory), + react: app.frameworks?.includes(Framework.REACT) ?? false, + angular: app.frameworks?.includes(Framework.ANGULAR) ?? false, }; - for (const f of app.frameworks || []) { - javascriptSdk[f] = true; + if (experiments.isEnabled("fdcrealtime")) { + javascriptSdk.clientCache = {}; } if (!isArray(generate?.javascriptSdk)) { generate.javascriptSdk = generate.javascriptSdk ? [generate.javascriptSdk] : []; } - if (!generate.javascriptSdk.some((s) => s.outputDir === javascriptSdk.outputDir)) { + const existing = generate.javascriptSdk.find((s) => s.outputDir === javascriptSdk.outputDir); + if (!existing) { generate.javascriptSdk.push(javascriptSdk); } break; @@ -403,39 +409,51 @@ export function addSdkGenerateToConnectorYaml( outputDir: path.relative(connectorDir, path.join(appDir, `lib/dataconnect_generated`)), package: "dataconnect_generated/generated.dart", }; + if (experiments.isEnabled("fdcrealtime")) { + dartSdk.clientCache = {}; + } if (!isArray(generate?.dartSdk)) { generate.dartSdk = generate.dartSdk ? [generate.dartSdk] : []; } - if (!generate.dartSdk.some((s) => s.outputDir === dartSdk.outputDir)) { + const existing = generate.dartSdk.find((s) => s.outputDir === dartSdk.outputDir); + if (!existing) { generate.dartSdk.push(dartSdk); } break; } case Platform.ANDROID: { const kotlinSdk: KotlinSDK = { - outputDir: path.relative(connectorDir, path.join(appDir, `src/main/kotlin`)), + outputDir: path.relative(connectorDir, path.join(app.directory, "src/main/kotlin")), package: `com.google.firebase.dataconnect.generated`, }; + if (experiments.isEnabled("fdcrealtime")) { + kotlinSdk.clientCache = {}; + } if (!isArray(generate?.kotlinSdk)) { generate.kotlinSdk = generate.kotlinSdk ? [generate.kotlinSdk] : []; } - if (!generate.kotlinSdk.some((s) => s.outputDir === kotlinSdk.outputDir)) { + const existing = generate.kotlinSdk.find((s) => s.outputDir === kotlinSdk.outputDir); + if (!existing) { generate.kotlinSdk.push(kotlinSdk); } break; } case Platform.IOS: { - const swiftSdk = { + const swiftSdk: SwiftSDK = { outputDir: path.relative( connectorDir, path.join(app.directory, `../FirebaseDataConnectGenerated`), ), package: "DataConnectGenerated", }; + if (experiments.isEnabled("fdcrealtime")) { + swiftSdk.clientCache = {}; + } if (!isArray(generate?.swiftSdk)) { generate.swiftSdk = generate.swiftSdk ? [generate.swiftSdk] : []; } - if (!generate.swiftSdk.some((s) => s.outputDir === swiftSdk.outputDir)) { + const existing = generate.swiftSdk.find((s) => s.outputDir === swiftSdk.outputDir); + if (!existing) { generate.swiftSdk.push(swiftSdk); } break;