10

I am trying to use Firebase Parameterized configuration with Typescript for Cloud Functions. Specifically, I am trying to use them at deploy time to specify a service account to use because I have three environments (dev, staging, prod) in separate firebase projects, with separate firestore databases.

I am following the instructions here https://firebase.google.com/docs/functions/config-env

I have no issue accessing these environment variable at runtime like in the instructions by calling .value()

I define my service account environment variable like so:

config.ts

import { defineString } from "firebase-functions/params"

export const SERVICE_ACCOUNT = defineString("SERVICE_ACCOUNT")

.env.

SERVICE_ACCOUNT = './service-account-dev.json'

Then when I would like to use this environment variable at deploy time I get some errors

index.ts

import * as admin from "firebase-admin"
import { SERVICE_ACCOUNT } from "./config"

admin.initializeApp({
  credential: admin.credential.cert(SERVICE_ACCOUNT),
})

Typescript error: "Argument of type 'StringParam' is not assignable to parameter of type 'string | ServiceAccount'.ts(2345)"

And then, when I try to get the value here like so: index.ts

import * as admin from "firebase-admin"
import { SERVICE_ACCOUNT } from "./config"

admin.initializeApp({
  credential: admin.credential.cert(SERVICE_ACCOUNT.value()),
})

With this code I now get no issues from typescript because the value is a string, but instead I get the an error when deploying to firebase (which is expected and mentioned in the instructions I linked at the top).

The error is as follows:

{"severity":"WARNING","message":"params.SERVICE_ACCOUNT.value() invoked during function deployment, instead of during runtime."}
{"severity":"WARNING","message":"This is usually a mistake. In configs, use Params directly without calling .value()."}
{"severity":"WARNING","message":"example: { memory: memoryParam } not { memory: memoryParam.value() }"}

So the issue I have is that I cannot use just the Param because typescript won't compile, and then when I get the value from the param to make typescript happy I cannot deploy.

Can anyone help me out here? Thanks in advance

I am using the following packages for firebase functions and admin:

"firebase-admin": "^11.3.0",
"firebase-functions": "^4.1.0",
2
  • Did you solve this issue? I'm having the same warnings. Commented Jan 31, 2023 at 16:50
  • @doup I did not exactly solve this issue. I simply used a workaround where I copy the contents of the correct environments service account file into service-account.json, and then in my index.ts my credential is admin.credential.cert("./service-account.json"). I do this in a script I created in package.json, e.g. "prepare:dev": "cp ./service-account-dev.json ./service-account.json && firebase use dev" Commented Feb 2, 2023 at 12:27

3 Answers 3

1

This is likely to be because it's treating your

admin.initializeApp({
  credential: admin.credential.cert(SERVICE_ACCOUNT),
})

As being at "build time", rather than as run time, if it's outside of the main function execution.

If you initializeApp inside the https.onCall(...) => {, (or onUpdate or whichever flavour you're using) block itself, it should work as expected.

I have seen other instances where the typing is incorrect, in some of the runWith options. (see https://github.com/firebase/firebase-tools/issues/5347) but casting to any makes the TS build work.

Sign up to request clarification or add additional context in comments.

Comments

1

I find this work for me.

import { defineString } from "firebase-functions/params";

const environment = defineString("ENVIRONMENT", {
  default: "development",
  description: "this define the env is on production or development or test",
});

if (environment.equals("production").thenElse(true, false)) {
  admin.initializeApp({
    credential: admin.credential.cert(require("./serviceAccountKey.json")),
  });
} else {
  // for development and test database
  admin.initializeApp({
    credential: admin.credential.cert(
      require("../../test/config/testingServiceAccountKey.json")
    ),
  });
}

Comments

-3

defineString().value is a getter function. so you should use it as a parameter, not a method.

import * as admin from "firebase-admin"
import { SERVICE_ACCOUNT } from "./config"

admin.initializeApp({
  credential: admin.credential.cert(SERVICE_ACCOUNT.value),
})

1 Comment

I don't mean to be rude, but try to avoid things that don't actually belongs to the questions, such like "happy new year", usually it avoids some that would read your answer to actually read it. It isn't a mistake, its just a tip, hope you understand! Happy new year for you too!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.