You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extension required: true on params that carry a default (ENABLE_AUTO_DISCOVERY, ENABLE_DISCUSSION_OPTION_OVERRIDES, ENABLE_GENKIT_MONITORING) is not reproduced as a blocking prompt; kit params with a default are never prompted as required. Platform difference, no value change.
Service account params have been removed in kits, as they conflict with declarative security (requiresRole) stuff.
LOCATION params have been removed in kits, as kits builds this feature in.
Some changes may be due to dependency upgrades, or more recent Node versions.
Extensions previously didn't support a number type, so they used text/string type with regex (e.g. validation: ^[0-9]) for validation. Kits now use defineInt, so they don't require the regex validation.
required: defaults to true when omitted in extension.yaml, and several extensions omit it on params their own code and descriptions treat as optional (BACKUP_COLLECTION, DEFAULT_REPLY_TO, USERS_COLLECTION, TEMPLATES_COLLECTION). Kits match the code behaviour (optional, empty → undefined), not the yaml.
defineSecret cannot be optional — SecretParamOptions only takes label/description, so any bound secret must exist at deploy. Extension params declared type: secret, required: false (API_KEY, GOOGLE_AI_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY, and the send-email SMTP/OAuth secrets) therefore become mandatory-at-deploy in kits. Platform constraint, not a kit choice.
Where an extension's yaml default disagreed with its own code fallback (firestore-genai-chatbot / firestore-vector-searchCOLLECTION_NAME, delete-user-dataAUTO_DISCOVERY_SEARCH_FIELDS), kits standardise on the yaml default.
No firebase-functions/params equivalent of the ${DATABASE_INSTANCE} system param. In the extension, the built-in FIREBASE_CONFIG.databaseURL resolves without prompting. This is something kit has to handle itself. Only applicable in rtdb-limit-child-nodes extension/kit.
IMG_BUCKET / EXTENSION_BUCKET use the params BUCKET_PICKER (a ResourceInput), which cannot also carry a validationRegex or example, so those two params keep the picker instead of the extensions' regex and example. The picker constrains input to real buckets, which is stronger, and this will stay as is.
Function resource properties (timeout, memory, maxInstances from each extension's resources[].properties) have not been systematically compared against the kit function definitions, and no sweep is planned — this may be something firebase-tools handles itself when deploying kits.
Kits have no deploy-time status surface. Extensions reported progress and failures through getExtensions().runtime().setProcessingState(...); nothing equivalent exists for kits, so deploy-time outcomes are only visible in function logs. Affects bigquery-firestore-export (10 call sites), firestore-bigquery-export (lifecycle hooks), firestore-translate-text (backfill) and firestore-vector-search (backfill gating).
billingRequired: true has no kit equivalent, so kits cannot declare the billing requirement that firestore-translate-text and rtdb-limit-child-nodes declared in their yaml.
rtdb-limit-child-nodes renamed NODE_PATH to RTDB_NODE_PATH and will keep it: Node.js reserves NODE_PATH for module resolution, so the original name is overwritten at runtime.
Event payload shapes changed with the gen1 to gen2 migration: { change, context } became { data, params } (firestore-counter, firestore-translate-text), and speech-to-text now publishes { message, stack } where the extension published a non-enumerable Error that serialised to {}. Consumers reading context.params need updating.
firestore-vector-search publishes Eventarc events where the extension published none (it declared the event types in extension.yaml but never published them). The kit exceeds the extension here rather than falling short.
extension.yaml used to have a reason for roles and APIs. Now with kits, only requiresAPI accepts a reason param. requiresRole doesn't accept a reason.
Cross-kit: AI-provider location fallback — firestore-genai-chatbotVERTEX_AI_MODEL_LOCATION=null no longer means "function region" (§3); firestore-translate-text vertex region from FUNCTION_REGION/genkit default (§2); firestore-vector-search same class (§5) — knock-on of the LOCATION removal, one decision — issue decision(kits): AI-provider location fallback after the LOCATION removal #3028 - as an example fbe had DATABASE_REGION (or similar) that is removed in the kit now, on kits branch.
bigquery-firestore-export: BigQuery job/billing project now config.projectId — the extension used the ADC default (§10) — DECISION: no change, no Notes entry — on a deployed function projectID (FIREBASE_CONFIG.projectId) and ADC (GCLOUD_PROJECT) resolve to the same project, and the client project is only used for the job, never a resource reference (the single createQueryJob query is fully qualified). Diverges only for local runs or a foreign GOOGLE_APPLICATION_CREDENTIALS key. Same idiom as delete-user-data Pub/Sub and the firestore-incremental-capture extension @IzaakGough
firestore-bigquery-export: no onConfigure lifecycle equivalent (§3a) — DECISION: investigate — investigated: no gap, afterRedeploy covers it. firebase-tools hashes each endpoint as source+env+secrets, so an .env-only change marks the endpoint for update, which counts as a resource modification and fires afterRedeploy (release/lifecycle.js skips the hook only when nothing changed). The extension wired onUpdate and onConfigure to the same handler, and the kit wires afterRedeploy to the same idempotent setupBigQuerySync reconcile task, so behaviour is equivalent
firestore-translate-text: backfill removed, along with the "only fill missing languages" semantics — DECISION: no fix — the extension's backfill never deploys (resource and DO_BACKFILL commented out in its yaml), so no-backfill is parity — issue feat(firestore-translate-text): design backfill #3032
Notes candidates (won't fix — differences to justify in Notes instead)
rtdb-limit-child-nodes: NODE_PATH rename (Node.js reserves the name)
No deploy-time status surface in kits (no setProcessingState equivalent) — firestore-bigquery-export §3d, firestore-translate-text, firestore-vector-search §9d
billingRequired: true has no kit equivalent (firestore-translate-text, rtdb-limit-child-nodes)
firestore-send-emailOAUTH_SECURE and speech-to-textENABLE_AUTOMATIC_PUNCTUATION advertise a default of true, but an unset variable reads false in both the extension (=== "true") and the kit (BooleanParam). Inherited, reproduced for parity, pinned by tests in fix(kits): restore extension select params for yes/no config parity #3148
Tracking board: https://github.com/orgs/firebase/projects/38/views/1
Below are comments for each extension to kit migration. Each comment displays the differences between the extension and the corresponding kit.
Valid differences (Stale)
yes/nokeepdefineStringwith those values and the extension's=== "yes"coercion (fix(firestore-bigquery-export): take the extension's yes/no values for snapshot syntax and old data #3145 forfirestore-bigquery-export, fix(kits): restore extension select params for yes/no config parity #3148 fordelete-user-dataandfirestore-genai-chatbot); an extension.envis reusable as-is. Selects that storedtrue/falsekeepdefineBoolean, which parses them like the extension's=== "true", with the extension's option labels restored viaselect<boolean>(fix(kits): restore extension select params for yes/no config parity #3148).required: trueon params that carry a default (ENABLE_AUTO_DISCOVERY,ENABLE_DISCUSSION_OPTION_OVERRIDES,ENABLE_GENKIT_MONITORING) is not reproduced as a blocking prompt; kit params with a default are never prompted as required. Platform difference, no value change.storage-resize-imagesMAKE_PUBLICisdefineStringwith"true"/"false"values rather thandefineBoolean: firebase-tools' select prompt ignores a non-stringdefaultand preselects the first option (functions params: select prompt ignores a non-string default and preselects the first option firebase-tools#11053), which leftYeshighlighted where the extension preselectedNo. Stored values unchanged (fix(kits): restore extension select params for yes/no config parity #3148).requiresRole) stuff.LOCATIONparams have been removed in kits, as kits builds this feature in.validation: ^[0-9]) for validation. Kits now usedefineInt, so they don't require the regex validation.required:defaults totruewhen omitted inextension.yaml, and several extensions omit it on params their own code and descriptions treat as optional (BACKUP_COLLECTION,DEFAULT_REPLY_TO,USERS_COLLECTION,TEMPLATES_COLLECTION). Kits match the code behaviour (optional, empty →undefined), not the yaml.defineSecretcannot be optional —SecretParamOptionsonly takeslabel/description, so any bound secret must exist at deploy. Extension params declaredtype: secret, required: false(API_KEY,GOOGLE_AI_API_KEY,GEMINI_API_KEY,OPENAI_API_KEY, and the send-email SMTP/OAuth secrets) therefore become mandatory-at-deploy in kits. Platform constraint, not a kit choice.firestore-genai-chatbot/firestore-vector-searchCOLLECTION_NAME,delete-user-dataAUTO_DISCOVERY_SEARCH_FIELDS), kits standardise on the yaml default.firebase-functions/paramsequivalent of the${DATABASE_INSTANCE}system param. In the extension, the built-inFIREBASE_CONFIG.databaseURLresolves without prompting. This is something kit has to handle itself. Only applicable inrtdb-limit-child-nodesextension/kit.IMG_BUCKET/EXTENSION_BUCKETuse the paramsBUCKET_PICKER(aResourceInput), which cannot also carry avalidationRegexorexample, so those two params keep the picker instead of the extensions' regex and example. The picker constrains input to real buckets, which is stronger, and this will stay as is.timeout,memory,maxInstancesfrom each extension'sresources[].properties) have not been systematically compared against the kit function definitions, and no sweep is planned — this may be something firebase-tools handles itself when deploying kits.getExtensions().runtime().setProcessingState(...); nothing equivalent exists for kits, so deploy-time outcomes are only visible in function logs. Affectsbigquery-firestore-export(10 call sites),firestore-bigquery-export(lifecycle hooks),firestore-translate-text(backfill) andfirestore-vector-search(backfill gating).billingRequired: truehas no kit equivalent, so kits cannot declare the billing requirement thatfirestore-translate-textandrtdb-limit-child-nodesdeclared in their yaml.rtdb-limit-child-nodesrenamedNODE_PATHtoRTDB_NODE_PATHand will keep it: Node.js reservesNODE_PATHfor module resolution, so the original name is overwritten at runtime.{ change, context }became{ data, params }(firestore-counter,firestore-translate-text), andspeech-to-textnow publishes{ message, stack }where the extension published a non-enumerableErrorthat serialised to{}. Consumers readingcontext.paramsneed updating.firestore-vector-searchpublishes Eventarc events where the extension published none (it declared the event types inextension.yamlbut never published them). The kit exceeds the extension here rather than falling short.extension.yamlused to have areasonfor roles and APIs. Now with kits, onlyrequiresAPIaccepts a reason param.requiresRoledoesn't accept areason.Remaining parity work
Correctness / production-firing
roles/eventarc.publisher(firestore-counter,firestore-translate-text,firestore-bigquery-export,speech-to-text); withEVENTARC_CHANNELset the awaited publish 403s and the function fails before doing any work - issue kits: declare roles/eventarc.publisher so event publishing does not 403 #3125 - fix in fix(kits): restore the extensions' event payload shapes #3098 commit f69b065 (8 publishing kits, not 4; PR needs rebase, not yet deploy-verified) @CorieWMigration / consumer breaks
firestore-vector-search: status field shape change —status.<instanceId>.stateconsumers break (§6) - issue decision(firestore-vector-search): status field shape, nested per-instance vs flat #3139 (decision; fix(firestore-vector-search): restore terminal-state skip on embedOnWrite #3092 leaves the shape out of scope)firestore-vector-search: OpenAI index dimension does not match the vectors written —dimensionFor()returns 512 for openai (kits/firestore-vector-search/src/export-config.ts:105) while ada-002 writes 1536 (src/embeddings/client/text/open_ai.ts:34), sofindNearestcannot use the index. Inherited from the extension and reproduced exactly by fix(firestore-vector-search): restore the extension's embedding defaults #3096; decision(firestore-vector-search): embedding model and dimension defaults #3029 decided the model, not the dimension — issue decision(firestore-vector-search): OpenAI vector index is 512 dimensions while the vectors are 1536 #3105.createIndexnever compares dimension (src/queries/setup.ts:49-56), so any fix needs a delete-the-old-index migration notefirestore-bigquery-export: legacy back-compat event types dropped — the extension published bothfirebase.extensions.firestore-counter.v1.*(legacy) and…firestore-bigquery-export.v1.*; the kit publishes only the new ones — issue fix(firestore-bigquery-export): republish the legacy firestore-counter event types #3108 — fix(firestore-bigquery-export): republish the legacy firestore-counter event types #3111 @cabljac @CorieWspeech-to-text: transcoded.wavlands in a different Storage location (§1, including the.txtpath's retainedreplace("tmp/", …)) -.txtremnant fixed in fix(speech-to-text): stop stripping tmp/ from the .txt transcription path #3073; the.wavlocation - issue decision(speech-to-text): transcoded .wav lands in a different Storage location #3140 - DECISION: parity, reproduce the extension'stmp/-prefixed paths (double slash included) - fix(speech-to-text): write the transcoded .wav under tmp/ like the extension #3157 (open) @cabljac{change, context}→{data, params}(firestore-counter§5,firestore-translate-text),speech-to-texterror{}→{message, stack}— decision recorded in issue decision(kits): event payload shape {change, context} vs {data, params} #3027 (open): NOT intentional gen2 design, fix — fix(kits): restore the extensions' event payload shapes #3098 @CorieWEvents gaps
Behavior divergence (fix or decide)
firestore-vector-search: re-embed-on-update flipped (the extension never re-embeds terminal docs) + ERROR-retry flipped (§6a/6b) — issue fix(firestore-vector-search): restore re-embed and ERROR-retry semantics #3011 DECISION: parity where possible with extension — fix(firestore-vector-search): restore terminal-state skip on embedOnWrite #3092 @CorieWfirestore-vector-search: backfill de-batched — per-document tasks and embedding calls, metadata-doc gate lost,collection().get()loads every document into memory → every redeploy re-embeds the whole collection (§9) — DECISION: fix, aim for parity — issue fix(firestore-vector-search): restore batched backfill #3012 — fix(firestore-vector-search): restore batched backfill #3097 @CorieWfirestore-genai-chatbot: startup fail-fast removed (validateRequiredEnvVars()) — DECISION: track as follow-up — issue fix(firestore-genai-chatbot): validate conditional config combinations at first invocation #3022firestore-genai-chatbotVERTEX_AI_MODEL_LOCATION=nullno longer means "function region" (§3);firestore-translate-textvertex region fromFUNCTION_REGION/genkit default (§2);firestore-vector-searchsame class (§5) — knock-on of theLOCATIONremoval, one decision — issue decision(kits): AI-provider location fallback after the LOCATION removal #3028 - as an example fbe had DATABASE_REGION (or similar) that is removed in the kit now, on kits branch.globalVertex AI endpoint. Partial coverage: vector search is untouched, and decision(kits): AI-provider location fallback after the LOCATION removal #3028’s explicit-region decision is not fully implemented. This task remains open.storage-resize-images: programmatic default flips —deleteOriginalunsetonSuccess→never;isAnimatedunsetfalse→true(§1–2) — DECISION: deleteOriginal parity (onSuccess); isAnimated stays true, the extension's unset-false was a shipped bug (|| undefined), fixed and documented in README — issue fix(storage-resize-images): restore programmatic defaults for deleteOriginal and isAnimated #3024 — fix(storage-resize-images): restore the extension's default for an omitted deleteOriginal #3100bigquery-firestore-export:DISPLAY_NAMEedits silently no-op — never added to the DTS update mask — issue fix(bigquery-firestore-export): DISPLAY_NAME edits silently no-op on update #3141 - fix(bigquery-firestore-export): apply DISPLAY_NAME changes on update #2980 (open)bigquery-firestore-export:TRANSFER_CONFIG_NAMEenables the extension's dead link-config branch — behavior beyond the extension (§3) — decide/Note fix(bigquery-firestore-export): notify this instance's topic when linking a config #2960firestore-translate-text:nullinput routes differently —typeof null === "object", so the extension sends{ input: null }totranslateMultipleand throws inObject.entries(functions/src/translate/translateMultiple.ts:35); the kit'sinput !== nullguard (kits/firestore-translate-text/src/translate/translateDocument.ts:44) routes it totranslateSingle, and fix(firestore-translate-text): stop coercing non-string input before translation #3109's test pins that (tests/translate-document.test.ts:116) — decide/Note - issue decision(firestore-translate-text): null input routes to translateSingle instead of throwing #3142Feature-scale (design first)
Notes candidates (won't fix — differences to justify in Notes instead)
Event payload shape, if ruled intentional gen2 design— ruled NOT intentional in issue decision(kits): event payload shape {change, context} vs {data, params} #3027 (open); fix in fix(kits): restore the extensions' event payload shapes #3098Minor / cosmetic (batchable)
storage-resize-images:FUNCTION_MEMORYprompt preselects512 MBwhere the extension preselected1 GB:defineIntselect withdefault: 1024whose first option is512, and the CLI ignores non-string select defaults (functions params: select prompt ignores a non-string default and preselects the first option firebase-tools#11053). Same class asMAKE_PUBLICin fix(kits): restore extension select params for yes/no config parity #3148; the only other non-string select across kits with a non-first default — issue storage-resize-images: FUNCTION_MEMORY prompt preselects 512 MB instead of the extension's 1 GB default #3156storage-resize-images: unknownIMAGE_TYPEvalues not rejected at config resolve time — issue feat(storage-resize-images): reject unknown IMAGE_TYPE values at config resolve time #3124 (milestone kits-follow-ups)Completed
Correctness / production-firing
bigquery-firestore-export: soft failures → hard failures — cases the extension reportedPROCESSING_COMPLETEnow throw underretry: true→ retry storms (§7a–7c, §8) - fix(bigquery-firestore-export): stop retrying deploy-time misconfigurations #2983 — fix(bigquery-firestore-export): stop retrying deploy-time misconfigurations #2983 @IzaakGough look into this, what should the kit behaviour be — fix(bigquery-firestore-export): stop retrying the two failures the extension treated as terminal #3086 (merged) stops retrying the two terminal failures; config-validation residual tracked in issue fix(bigquery-firestore-export): soft failures throw and retry-storm #3008firestore-send-email: SendGrid +AUTH_TYPE=OAuth2sends fail — secret gating forcesapiKey: undefined,setApiKeynever called — issue fix(firestore-send-email): SendGrid sends fail with AUTH_TYPE=OAuth2 #3009 (closed) — fix(firestore-send-email): keep SMTP_PASSWORD available so SendGrid works with AUTH_TYPE=OAuth2 #3089 (merged 2026-09-07)storage-resize-images: partial-env crashes — issue fix(storage-resize-images): degrade gracefully against a partial env #3138 (closed) - fix(storage-resize-images): degrade gracefully against a partial env #3002 (merged 2026-09-08)storage-resize-images: deletion risk — emptyimageTypes→ zero outputs counts as success → original deleted underon_success(§6) - fix(storage-resize-images): failed resize can delete the original image #3037 (merged)firestore-counter:deep-equalcalled without{ strict: true }in the worker (§1) - fix(firestore-counter): compare worker metadata with strict deep-equal #3072 (merged)storage-resize-images: content-filter region readsFUNCTION_REGIONand throws when absent; the extension fell back tous-central1(§5) - fix(storage-resize-images): restore the us-central1 content-filter fallback #3090 (merged)firestore-vector-search:queryOnWriteprefilterscast unvalidated — the extension zod-parses them (§7b) - fix(firestore-vector-search): validate prefilters on the query onWrite path #3065 (merged)firestore-vector-search:queryOnWriteself-retrigger loop (§7) - fix(firestore-vector-search): stop queryOnWrite retriggering itself #3038 (merged; stored-request guard, self-heals the stale-overwrite race — supersedes fix(firestore-vector-search): guard queryOnWrite with the extension's status #3095, closed 2026-09-08 as superseded)bigquery-firestore-export: Pub/Sub topic renamedext-→kit-, update path rewrotenotification_pubsub_topic(§4) - fix(bigquery-firestore-export): make the DTS notification topic configurable #3088 (merged; topic configurable viaPUB_SUB_TOPIC, set it to the oldext-topic to preserve notifications across migration)firestore-bigquery-export:DATABASE_REGIONused as function region —eur3/nam5/nam7aren't Cloud Run regions → deploy hard-fails (§2) - fix(firestore-bigquery-export): stop using DATABASE_REGION as the function region #3066 (merged, live-verified on a nam5 database; the same conflation is still live in firestore-send-email: fix(firestore-send-email): DATABASE_REGION used as function region breaks multi-region deploys #3069 (open), tracked under Remaining parity work. NOTE: fix(firestore-bigquery-export): stop using DATABASE_REGION as the function region #3066's param removal partially reverted by fix(firestore-bigquery-export): place functions from DATABASE_REGION with a multi-region mapping #3101, which restores DATABASE_REGION as a placement param with the dual-region mapping, per the firebase-tools team's minimal-divergence decision and upstream bug Functions deploy: region resolution runs before param substitution, parameterized Firestore trigger database silently falls back to us-central1 firebase-tools#11020)PROJECT_IDresolution — the extension readsprocess.env.PROJECT_ID(functions/src/config.ts:166), injected by the Extensions runtime, and defaultsBIGQUERY_PROJECT_IDto the${PROJECT_ID}system param; kits usefirebase-functions/paramsprojectID, which resolves fromFIREBASE_CONFIG.projectId. Surfaced by 🐛 [@firebase-function-kits/firestore-bigquery-export] afterFirstDeploy taskqueue initialization failed from missing PROJECT_ID #3120 (and the older 🐛 [firestore-bigquery-export] Project ID resolves to undefined in Gen2 / Cloud Run functions #2778). Only the shared change tracker was affected: its update-view path droppedbqProjectIdand fell back toprocess.env.PROJECT_ID- fixed in fix(firestore-bigquery-change-tracker): preserve BigQuery project on view updates, release 2.2.1 #3137 (merged, tracker 2.2.1, supersedes fix(bigquery): preserve project on view updates #3121). The kit picks it up via@firebaseextensions/firestore-bigquery-change-tracker@^2.2.1(chore(firestore-bigquery-export): bump firebase-admin to ^14.2.0 #3127, shipped in 0.0.2-rc.7) and the fix was verified live on dev-extensions-testing. Tracker follow-ups: [firestore-bigquery-change-tracker] BigQuery client project override clobbers ADC auto-detection when bqProjectId and PROJECT_ID are both unset #3143 (project override clobbers ADC), [firestore-bigquery-change-tracker] initializeLatestView update path mutates the shared RawChangelogViewSchema constant #3144 (shared view schema mutated on update)storage-resize-images:CONTENT_FILTER_LEVEL"Off" option stored the stringFalseinstead ofOFF, so every resize with the filter off threw at runtime — issue fix(storage-resize-images): the "Off" content-filter selection stores "False" and fails every event #3047 (closed) — fix(storage-resize-images): map the Off content-filter option to OFF #3064 (merged 2026-09-08; follow-ups fix(storage-resize-images): IS_ANIMATED select label is True, the extension says Yes #3123 label, feat(storage-resize-images): reject unknown IMAGE_TYPE values at config resolve time #3124 staleIMAGE_TYPEvalidation)firestore-send-email:DATABASE_REGIONused as function region — same conflation as firestore-bigquery-export fix(firestore-bigquery-export): stop using DATABASE_REGION as the function region #3066/fix(firestore-bigquery-export): place functions from DATABASE_REGION with a multi-region mapping #3101,eur3/nam5/nam7selectable so deploy hard-fails on a multi-region database — issue fix(firestore-send-email): DATABASE_REGION used as function region breaks multi-region deploys #3069 — fix(firestore-send-email): map DATABASE_REGION to a Cloud Run region for function placement #3102 (merged 2026-09-08)Migration / consumer breaks
yes/no.envbreak fordelete-user-dataENABLE_AUTO_DISCOVERYandfirestore-genai-chatbotENABLE_DISCUSSION_OPTION_OVERRIDES/ENABLE_GENKIT_MONITORING(same defect as firestore-bigquery-export kit: EXCLUDE_OLD_DATA and USE_NEW_SNAPSHOT_QUERY_SYNTAX read 'yes' as false #3126): nowdefineString+=== "yes", so an extension.envreads correctly. The same PR restores the extension's option labels on the 7true/falseselects (OAUTH_SECURE,DO_BACKFILL,UPDATE_ON_CONFIGURE,ENABLE_AUTOMATIC_PUNCTUATION,MAKE_PUBLIC,IS_ANIMATED,REGENERATE_TOKEN) and fixes theMAKE_PUBLICprompt preselectingYes(functions params: select prompt ignores a non-string default and preselects the first option firebase-tools#11053) — fix(kits): restore extension select params for yes/no config parity #3148 (merged 2026-09-08)firestore-vector-search: OpenAI model changed — ada-002 → 3-small@512, incompatible with existing indexes (§2) — decision recorded in issue decision(firestore-vector-search): embedding model and dimension defaults #3029 (revert to the extension's defaults) — fix(firestore-vector-search): restore the extension's embedding defaults #3096 (merged)firestore-vector-search: gemini/vertex embedding dimensions changed — extension hardcodedoutputDimensionality: 768with no truncation; kit passesconfig.dimensionand truncates the result (§5) — fix(firestore-vector-search): restore the extension's embedding defaults #3096 (merged)Events gaps
firestore-translate-text: early-returns on!event.datawithout emitting start/completion events; the extension always emitted both — issue fix(firestore-translate-text): always emit start and completion events #3020 @cabljac - fix(firestore-translate-text): emit start and completion events on every write #3149 (merged 2026-09-08)firestore-bigquery-export:onSuccessnever published, and the kit README claims it is — doc bug, small standalone fix - docs(firestore-bigquery-export): stop claiming the kit publishes onSuccess and onCompletion #3071 (merged; doc-only, no code change needed)firestore-vector-search: events published only fromhandleEmbedOnWrite— nothing from the query/backfill/update/init paths — fix(firestore-vector-search): stop publishing events the extension never sent #3094 (merged) resolves issue fix(firestore-vector-search): publish events from all paths #3016 by REMOVING the kit-only events instead (the extension never published any; parity) @CorieWBehavior divergence (fix or decide)
bigquery-firestore-export: BigQuery job/billing project nowconfig.projectId— the extension used the ADC default (§10) — DECISION: no change, no Notes entry — on a deployed functionprojectID(FIREBASE_CONFIG.projectId) and ADC (GCLOUD_PROJECT) resolve to the same project, and the client project is only used for the job, never a resource reference (the singlecreateQueryJobquery is fully qualified). Diverges only for local runs or a foreignGOOGLE_APPLICATION_CREDENTIALSkey. Same idiom asdelete-user-dataPub/Sub and thefirestore-incremental-captureextension @IzaakGoughfirestore-bigquery-export: noonConfigurelifecycle equivalent (§3a) — DECISION: investigate — investigated: no gap,afterRedeploycovers it. firebase-tools hashes each endpoint as source+env+secrets, so an.env-only change marks the endpoint for update, which counts as a resource modification and firesafterRedeploy(release/lifecycle.jsskips the hook only when nothing changed). The extension wiredonUpdateandonConfigureto the same handler, and the kit wiresafterRedeployto the same idempotentsetupBigQuerySyncreconcile task, so behaviour is equivalentfirestore-genai-chatbot: generation options now reach the model — DECISION: forward — README note in docs(kits): note that genai chatbot generation options now reach the model #3087 (merged)firestore-translate-text: newTranslationServiceper invocation — fresh client per event, performance (§5f) - fix(firestore-translate-text): construct the translation client once per process #3075 (merged)firestore-vector-search: vector-store error codes collapsed tounknown— the extension mapped 15 Firestore codes toHttpsError(§8) — DECISION: fix, parity — issue fix(firestore-vector-search): map vector-store errors to HttpsError codes #3015 — fix(firestore-vector-search): map vector-store errors to HttpsError codes #3093 (merged)firestore-send-email:TESTINGenv path gone — the kit cannot enter testing mode via env — issue fix(firestore-send-email): restore the TESTING env path #3107 — fix(firestore-send-email): restore the TESTING env path #3110 (merged) @CorieWfirestore-translate-text: non-string input coerced —42→"42"reaches the API (§4b) — minor, decide — DECISION: fix, aim for parity — issue fix(firestore-translate-text): stop coercing non-string input before translation #3106 — fix(firestore-translate-text): stop coercing non-string input before translation #3109 (merged) @CorieWbigquery-firestore-export: aTIMEcolumn is stored as the raw string BigQuery returned. The extension passed it toTimestamp.fromDate(new Date("10:30:00")), which throws and loses the whole run (no rows, no run document, nolatest), so no installed instance can have stored aTIMEvalue. Issue fix(bigquery-firestore-export): helper crashes on real BigQuery TIME values #3068. DECISION: store the string, extension unchanged: fix(bigquery-firestore-export): write BigQuery TIME values as strings #3146 (merged 2026-09-08)firestore-bigquery-export:EXCLUDE_OLD_DATA/USE_NEW_SNAPSHOT_QUERY_SYNTAX- extension acceptedyes/no, kitdefineBooleanacceptstrueonly, so a migrated.envwithyessilently reads as false - issue firestore-bigquery-export kit: EXCLUDE_OLD_DATA and USE_NEW_SNAPSHOT_QUERY_SYNTAX read 'yes' as false #3126 - DECISION: acceptyes/noalongside booleans - fix(firestore-bigquery-export): take the extension's yes/no values for snapshot syntax and old data #3145 (merged 2026-09-08, shipped in 0.0.2-rc.7)firestore-vector-search: multimodal unimplemented yet still an offeredEMBEDDING_PROVIDERvalue (§3) — DECISION: leave the value, removing it is a breaking config change and the extension has the same gap — fix(firestore-vector-search): remove the unimplemented multimodal provider value #3074 closed unmerged 2026-09-07, issue fix(firestore-vector-search): remove the unimplemented multimodal provider value #3014 closed; the non-functional provider itself is tracked in firestore-vector-search: multimodal embedding provider is non-functional in both extension and kit #3135 (kits-stable) @CorieWFeature-scale (design first)
firestore-counter: no client libraries (Android/iOS/Dart/node/web), shard format undocumented — closed as not planned (feat(firestore-counter): client libraries and shard format documentation #3033): migration only; the existing extension clients keep working against the unchanged shard formatfirestore-translate-text: backfill removed, along with the "only fill missing languages" semantics — DECISION: no fix — the extension's backfill never deploys (resource andDO_BACKFILLcommented out in its yaml), so no-backfill is parity — issue feat(firestore-translate-text): design backfill #3032firestore-bigquery-export: user-facing tooling absent — import, gen-schema-view, cross-project scripts, guides — DECISION: reference existing extension scripts/tooling — issue feat(firestore-bigquery-export): user-facing tooling #3034firestore-bigquery-export: write-path buffering — the extension buffers in Cloud Tasks; the kit rethrows and can hot-loop (§1) — issue feat(firestore-bigquery-export): design write-path buffering #3031 — DECISION: reinstate the Cloud Tasks buffer (option D, migration safety) — feat(firestore-bigquery-export): reinstate the Cloud Tasks write buffer #3103 closed 2026-09-07 in favour of stack #3132, bottom to top: chore(firestore-bigquery-export): bump firebase-admin to ^14.2.0 #3127 (firebase-admin ^14.2.0), feat(firestore-bigquery-export): add the sync task enqueue module #3128 (enqueue module), feat(firestore-bigquery-export): add the sync queue params #3129 (queue params), feat(firestore-bigquery-export): reinstate the Cloud Tasks write buffer #3130 (the behaviour change), docs(firestore-bigquery-export): document failure handling and recovery #3131 (docs), all merged into kits 2026-09-08 @cabljacNotes candidates (won't fix — differences to justify in Notes instead)
rtdb-limit-child-nodes:NODE_PATHrename (Node.js reserves the name)setProcessingStateequivalent) —firestore-bigquery-export§3d,firestore-translate-text,firestore-vector-search§9dbillingRequired: truehas no kit equivalent (firestore-translate-text,rtdb-limit-child-nodes)firestore-send-emailOAUTH_SECUREandspeech-to-textENABLE_AUTOMATIC_PUNCTUATIONadvertise a default oftrue, but an unset variable readsfalsein both the extension (=== "true") and the kit (BooleanParam). Inherited, reproduced for parity, pinned by tests in fix(kits): restore extension select params for yes/no config parity #3148Minor / cosmetic (batchable)
firestore-incremental-capture(7.3.2),firestore-send-emailandfirestore-vector-search(^7.3.2) are the only kits not onfirebase-functions@^7.3.3-rc.0; caret excludes prereleases so they run stable 7.3.2 - issue chore(kits): align firestore-incremental-capture, firestore-send-email and firestore-vector-search on firebase-functions ^7.3.3-rc.0 #3154 - chore(kits): align the last three kits on firebase-functions ^7.3.3-rc.0 #3155 (merged 2026-09-08)storage-resize-images:IS_ANIMATEDselect label readsTruewhere the extension saysYes(kits/storage-resize-images/src/config.ts:189vsextension.yaml:289-292) — issue fix(storage-resize-images): IS_ANIMATED select label is True, the extension says Yes #3123 — fix(kits): restore extension select params for yes/no config parity #3148 (merged 2026-09-08)firestore-bigquery-export:logs.start()called with no argument → logsundefined(§4) - chore(firestore-bigquery-export): drop unused config parameter from logs.start #3039 (merged)firestore-vector-search: custom-endpoint content-type check dropped (§4c) - fix(firestore-vector-search): reject non-JSON responses from the custom embeddings endpoint #3042 (merged)firestore-send-email:formatZodErrorinvalid_stringbranch dropped - fix(firestore-send-email): restore the invalid_string branch in formatZodError #3040 (merged)storage-resize-images:BLOCK_NONEaccepted where the extension threw (§4);cacheControlHeader: ""set literally (§7) - fix(storage-resize-images): reject BLOCK_NONE and treat empty Cache-Control as unset #3044 (merged)bigquery-firestore-export: dropped log helpers;MAX_STALENESSdoc example 8h → 4h - chore(bigquery-firestore-export): restore dropped log helper and MAX_STALENESS doc example #3045 (merged)delete-user-data:node-fetch@2where the extension used globalfetch- chore(delete-user-data): replace node-fetch with the Node global fetch #3041 (merged)firestore-translate-text: dead backfill remnants (filterLanguagesFn, unused log helpers) - chore(firestore-translate-text): delete dead backfill remnants from the kit #3043 (merged)firestore-genai-chatbot: localSafetySettingtype (no enum check);PROJECT_IDerror text - fix(firestore-genai-chatbot): type safety settings against the SDK enums and restore the PROJECT_ID error text #3046 (merged; whole minor-cleanups batch issue chore(kits): minor parity cleanups #3036 now complete)Coverage
bigquery-firestore-export: 1330 unit + 3170 E2E lines → 550 unit;ensureNotificationTopicuntested - test(bigquery-firestore-export): port legacy unit coverage into the kit #3056 (merged; 19 → 65 tests)firestore-genai-chatbot: emulator E2E + logger/overrides/config suites gone - test(firestore-genai-chatbot): port missing coverage from the legacy extension #3058 (merged; incl. emulator flow test, now run in PR CI via ci(kits): run emulator-gated kit suites on pull requests #3070)firestore-counter: no emulator tests - test(firestore-counter): port the active legacy emulator tests #3054 (merged; run in PR CI via ci(kits): run emulator-gated kit suites on pull requests #3070)delete-user-data: lazygetContext()path untested - closed by fix(delete-user-data): resolve the RTDB client on first use #2955 and test(delete-user-data): pin context memoization and client wiring #3055 (both merged)firestore-send-email: 2540 → 483 lines - test(firestore-send-email): port the legacy unit suites into the kit #3057 (merged; 121 tests, coverage audit found no decrease vs the legacy suite)Look into
FIREBASE_KIT_INSTANCE_ID? Yes - firebase-tools >= 15.27.0 injects it for kit instances (discovery, deploy, emulator, serve). It must be read viaprocess.env, never declared as a param (the params machinery only consults.env, and theFIREBASE_prefix is reserved there). Implemented for delete-user-data in fix(delete-user-data): read the kit instance id from FIREBASE_KIT_INSTANCE_ID #3060; remaining kits migrated in refactor(kits): read the kit instance id from FIREBASE_KIT_INSTANCE_ID #3122 (merged 2026-09-08, closes refactor(kits): migrate all kits from the INSTANCE_ID param to the injected FIREBASE_KIT_INSTANCE_ID #3063).