Skip to content

feat(functions): add functions:kits:install command - #10900

Merged
wandamora merged 14 commits into
mainfrom
morawand-kits-install
Aug 11, 2026
Merged

feat(functions): add functions:kits:install command#10900
wandamora merged 14 commits into
mainfrom
morawand-kits-install

Conversation

@wandamora

@wandamora wandamora commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Description

Adds the firebase functions:kits:install command (gated behind the kits experiment) to allow developers to install and configure reusable Cloud Function kits in their Firebase projects.

Note: this is the first iteration of the command that just handles the first instance in a single project.

Key Changes:

  • Command Registration & Experiment Gating: Registers functions:kits:install conditionally when the kits experiment is enabled.
  • Interactive & Flag Input: Accepts a --npm_package <package> flag, and interactively prompts for the kit and initial instance ID.
  • Package Parsing & Validation:
    • Parses scoped and unscoped package specifiers with optional versions/tags.
    • Sanitizes package names into valid kit identifiers.
    • Validates kit ID uniqueness and ensures instance IDs do not collide with existing codebase names or other kit instances in firebase.json.
  • Security & Third-Party Safeguards:
    • Differentiates first-party (@firebase-functions-kits/*) and third-party packages.
    • Inspects packages for npm-shrinkwrap.json via npm pack --dry-run --json to warn users when dependencies are unlocked.
    • Prompts for explicit user confirmation before installing third-party kits.
    • Installs third-party packages with --ignore-scripts for safety.
  • Wrapper Project Scaffolding:
    • Scaffolds a wrapper directory under function-kits/<kit-id>/ containing package.json, tsconfig.json, .gitignore, and src/index.ts from templates.
    • Generates index.ts using templates/init/functions/typescript/index-kit.ts, re-exporting the kit package with customizable global function parameters.
    • Automatically runs npm install and npm run build.
  • Configuration Updates: Adds the kit configuration block and instance mapping into firebase.json.
  • Testing: Comprehensive unit test suite in src/commands/functions-kits-install.spec.ts.

Scenarios Tested

  • Experiment gating: Verified error is thrown when kits experiment is disabled.
  • Precondition checks: Verified error when run outside a Firebase project directory (firebase.json missing).
  • Package specifier parsing for scoped/unscoped packages with and without versions.
  • Package name sanitization to valid kit identifiers (length truncation, character filtering).
  • Third-party package detection and warnings for packages without npm-shrinkwrap.json.
  • User confirmation flow cancellation / acceptance for third-party kits.
  • Validated that third-party kits run npm install --ignore-scripts.
  • Kit installation end-to-end scaffolding (package.json, tsconfig.json, index.ts, firebase.json).
  • Conflict validations:
    • Duplicate functions.kit ID in firebase.json.
    • Collision between kit instanceId and existing function codebase name.

Sample Commands

# Enable the kits experiment
firebase experiments:enable kits

# Install a package CLI
firebase functions:kits:install --npm_package @invertase/example-firebase-kit-hello-world@0.1.0

@wiz-9635d3485b

wiz-9635d3485b Bot commented Aug 7, 2026

Copy link
Copy Markdown

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities -
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings 22 Medium
Software Management Finding Software Management Findings -
Total 22 Medium

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try the Wiz Code extension for VS Code, JetBrains, or Visual Studio.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the functions:kits:install command, allowing users to install Cloud Function kits into their Firebase projects. It includes implementation logic, unit tests, command registration under the kits experiment, and a TypeScript entry point template. The review feedback highlights two key areas for improvement: first, a potential runtime crash in functions-kits-install.ts due to unsafe direct access of options.config.src after using optional chaining; second, the need to throw a FirebaseError immediately if parsing the package.nolint.json template fails, rather than silently continuing with an empty object and causing downstream build failures.

Comment thread src/commands/functions-kits-install.ts Outdated
Comment thread src/commands/functions-kits-install.ts
@wandamora
wandamora force-pushed the morawand-kits-install branch from 2aeea99 to e4b08d8 Compare August 7, 2026 00:11
- throw error for failing to parse template
- remove redundant ? for options.config.src, it shouldn't be undefined or null
@wandamora
wandamora force-pushed the morawand-kits-install branch from 073b681 to 2872d49 Compare August 7, 2026 17:09
package.json, tsconfig.json, and .gitignore should live in the root
of the kit, and index.ts will be in /src.
- Prompt for kit ID
- Update npm shrinkwrap warning
- change FIREBASE_FUNCTION_KIT_REGION param to FUNCTION_KIT_REGION
@wandamora
wandamora marked this pull request as ready for review August 7, 2026 18:55
@wandamora
wandamora requested review from ajperel and inlined August 7, 2026 18:55

@ajperel ajperel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for getting this out!

A bunch of minor comments and questions and a few things we should iron out through discussion.

const res = parsePackageSpecifier("my-kit@^2.0.0");
expect(res).to.deep.equal({
packageName: "my-kit",
version: "^2.0.0",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably also good to test release candidate versions since we'll use them

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or tags like @latest

technically npm distinguished between versions and tags but maybe we can just call it all version and get away with that?

Thoughts @inlined ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added more tests.

Comment thread src/commands/functions-kits-install.spec.ts
Comment thread src/commands/functions-kits-install.spec.ts Outdated
const INDEX_KIT_TEMPLATE = readTemplateSync("init/functions/typescript/index-kit.ts");

export interface FunctionsKitsInstallOptions extends Options {
npm_package?: string;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I see this.... I am again debating between this and

--package
(future) --package_manager

Pros:

  • We only ever need 2 flags (I hope)
  • Maybe easier to re-use logic in the future in cases where like... yarn packages and npm packages are the same since they are both npm behind the scenes

Cons:

  • Users not using npm have to always specify two flags instead of one.

I am still very torn. Curious what you and @inlined think after getting into it more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel that strongly either way TBH. I preferred package and package_manager to pave the way to support other package types in the future, but I also see the argument that we're implying the utility is larger than it is.

Comment thread src/commands/functions-kits-install.ts
Comment thread src/commands/functions-kits-install.ts
await options.config.askWriteProjectFile(relIndexTsPath, indexContent);
}

const installArgs = isThirdParty ? ["install", "--ignore-scripts"] : ["install"];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should just always ignore scripts. Yes, we could technically trust ours more... but when would we use them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, but we can leave it as is. We can always change it if we find a reason to.

const newKitConfig: KitFunctionConfig = {
kit: kitId,
sourcePackage: {
id: packageName,

@ajperel ajperel Aug 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is 100% what we put in the design doc... but as I brush up while reviewing...
none of the package systems talk about ids. They talk about package / distribution names. I wonder if we should also name this name. But.... maybe not a big deal? If we did want to do it maybe easier in a separate follow up change? Thoughts.

package systems also talk about the full spec (including version, etc.) but we're not storing that and I don't think we should since it'll get out of date.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair nit, let's keep it ID here and change it in a follow-up.

Comment thread templates/init/functions/typescript/index-kit.ts Outdated
Comment thread templates/init/functions/typescript/index-kit.ts Outdated
wandamora and others added 3 commits August 10, 2026 18:11
* Rename parsePackageSpecifier to parseNpmPackageSpecifier
* Add validateNpmPackageName to validate npm package format and reject multiple slashes
* Simplify sanitizePackageNameToKitName by removing redundant regex replacement
* Tighten isThirdPartyPackage to strictly match @firebase-functions-kits/ scope
* Make npm-shrinkwrap check independent of package origin and prompt if unshrinkwrapped
* Fix typo in shrinkwrap warning message
* Collect existing codebase and instance IDs upfront to prevent mutation side-effects during validation
* Refactor validateKitInstances to accept Iterable<string> with a default Set and add JSDoc param documentation
* Add rejection and tests for instance ID collisions across multiple kits
* Define FUNCTION_KITS_DIR constant for directory paths
* Update command and option descriptions to use function kit terminology
* Add explanatory comment before configuring wrapper package.json
* Refactor index-kit.ts template to use params namespace import and improve option comments
* Add unit tests for package name validation, RC/tag parsing, scope spoofing, independent shrinkwrap checks, and standalone validateKitInstances

@ajperel ajperel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fast iteration.

Comment thread src/commands/functions-kits-install.spec.ts
Comment thread src/commands/functions-kits-install.spec.ts Outdated
Comment thread src/commands/functions-kits-install.ts Outdated
Comment thread src/commands/functions-kits-install.ts Outdated
Comment thread src/commands/functions-kits-install.ts Outdated
Comment thread src/commands/functions-kits-install.ts
Comment thread src/functions/projectConfig.ts Outdated
Comment thread templates/init/functions/typescript/index-kit.ts Outdated
wandamora and others added 5 commits August 11, 2026 00:06
- Split format validation into `validateKitInstanceId` for single instance ID checking.
- Renamed the collection helper to `validateAndAddKitInstances` to explicitly signal adding validated IDs to the project set.
- Updated `functions:kits:install` prompt validation and tests accordingly.
@wandamora
wandamora enabled auto-merge (squash) August 11, 2026 15:50
@wandamora
wandamora merged commit a943b95 into main Aug 11, 2026
60 of 64 checks passed
@wandamora
wandamora deleted the morawand-kits-install branch August 11, 2026 15:54
yuichi0301 pushed a commit to yuichi0301/firebase-tools that referenced this pull request Aug 16, 2026
* Add kits:install command

* Address GCA comments

- throw error for failing to parse template
- remove redundant ? for options.config.src, it shouldn't be undefined or null

* Update source tree

package.json, tsconfig.json, and .gitignore should live in the root
of the kit, and index.ts will be in /src.

* Few more changes

- Prompt for kit ID
- Update npm shrinkwrap warning
- change FIREBASE_FUNCTION_KIT_REGION param to FUNCTION_KIT_REGION

* Update 3p test

* feat: address review feedback for functions:kits:install

* Rename parsePackageSpecifier to parseNpmPackageSpecifier
* Add validateNpmPackageName to validate npm package format and reject multiple slashes
* Simplify sanitizePackageNameToKitName by removing redundant regex replacement
* Tighten isThirdPartyPackage to strictly match @firebase-functions-kits/ scope
* Make npm-shrinkwrap check independent of package origin and prompt if unshrinkwrapped
* Fix typo in shrinkwrap warning message
* Collect existing codebase and instance IDs upfront to prevent mutation side-effects during validation
* Refactor validateKitInstances to accept Iterable<string> with a default Set and add JSDoc param documentation
* Add rejection and tests for instance ID collisions across multiple kits
* Define FUNCTION_KITS_DIR constant for directory paths
* Update command and option descriptions to use function kit terminology
* Add explanatory comment before configuring wrapper package.json
* Refactor index-kit.ts template to use params namespace import and improve option comments
* Add unit tests for package name validation, RC/tag parsing, scope spoofing, independent shrinkwrap checks, and standalone validateKitInstances

* Generate new kit ids defaults if taken

* Update index-kit.ts template

* Update prompts for 3P and adding instances

* Refactor valiateKitInstances

- Split format validation into `validateKitInstanceId` for single instance ID checking.
- Renamed the collection helper to `validateAndAddKitInstances` to explicitly signal adding validated IDs to the project set.
- Updated `functions:kits:install` prompt validation and tests accordingly.

* formatting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants