-
Notifications
You must be signed in to change notification settings - Fork 81
Agent Skills for CF3 V1-V2 Migration #60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
shettyvarun268
wants to merge
7
commits into
firebase:main
Choose a base branch
from
shettyvarun268:feature/v1-v2-migration-skill
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
be27c67
Initial Pass
shettyvarun268 06fffc6
improving reference documents
shettyvarun268 00a1b54
Addressing review comments
shettyvarun268 2793d38
Update destructuring shim documentation
shettyvarun268 2836df2
improvements for functions.config() migration
shettyvarun268 6fc753f
Update firebase-v1-v2-migration skill with V2 SDK features, import co…
shettyvarun268 aa375f6
Format markdown files with mdformat --wrap 80
shettyvarun268 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| --- | ||
| name: firebase-v1-v2-migration | ||
| description: Use this skill when a user wants to upgrade their legacy Firebase Functions from V1 (GCF 1st Gen) to V2 (GCF 2nd Gen) safely without rewriting their internal business logic. This skill relies on the Destructuring Compatibility Shim. | ||
| --- | ||
| # Prerequisites | ||
| Please ensure the workspace is ready for V2 before attempting a code migration: | ||
| 1. **Configuration Check**: Ensure the workspace has transitioned away from functions.config() to Parameterized Configuration or standard environment variables. | ||
| 2. **Dependencies**: The project must be using firebase-functions version that supports V2 (>= 4.0.0). | ||
|
|
||
| # 🔍 Pre-Migration Checklist | ||
| Before modifying any code, the agent should run a quick scan: | ||
| 1. **Scan for legacy configs**: Run a `grep` or text search for usages of `functions.config()`. | ||
| - **Action**: If found, **stop and warn the user** that these configs will evaluate to `undefined` in V2 unless they migrate to Parameterized Configuration or standard `.env` variables first. | ||
|
|
||
| # Principles of Safe Migration | ||
| Always follow these principles to ensure zero-touch logic migration: | ||
| 1. **Use Context-Aware Editing over Global Regex**: Never use naive find-and-replace. Rely on syntax-aware editing (such as an AI agent reading the file context and making precise edits, or tools like ts-morph/ast parsers) to ensure context isolation. | ||
| 2. **Signature Modernization with Destructuring**: Do NOT rewrite the internal variable usages of context or params inside the function body. Instead, use JavaScript's native object destructuring in the new V2 signature parameters. | ||
|
|
||
| ### 🛡️ Example Transformation | ||
|
|
||
| #### Before (V1 Legacy) | ||
| ```typescript | ||
| import * as functions from "firebase-functions"; | ||
| export const processOrder = functions.pubsub.topic("orders").onPublish((message, context) => { | ||
| const orderId = message.json.id; | ||
| console.log(`Processing order ${orderId} at ${context.timestamp}`); | ||
| }); | ||
| ``` | ||
|
|
||
| #### After (V2 Target - Safe Migration) | ||
| ```typescript | ||
| import { onMessagePublished } from "firebase-functions/v2/pubsub"; | ||
| // Using direct object destructuring in the signature! | ||
| export const processOrder = onMessagePublished("orders", ({ message, context }) => { | ||
| const orderId = message.json.id; // Legacy logic remains untouched! | ||
| console.log(`Processing order ${orderId} at ${context.timestamp}`); | ||
| }); | ||
| ``` | ||
|
|
||
| # Verification | ||
| After making any migration edits, immediately run the following verification steps: | ||
| 1. Run `npm run build` to ensure the TypeScript compiler is happy with the types and parameters. | ||
| 2. Run `npm test` to verify no regressions occurred in existing unit tests. | ||
|
|
||
| > [!WARNING] | ||
| > **Test Signature Mismatch**: The destructuring shim changes the function signature from two arguments `(data, context)` to a single destructured object `({ message, context })`. | ||
| > | ||
| > Existing V1 unit tests that invoke the function with two parameters separately (e.g., `myFn(mockData, mockContext)`) **will fail** because the function treats `mockData` as the entire event object. You will need to update test calls to pass a single object: `myFn({ message: mockData, context: mockContext })`. | ||
|
shettyvarun268 marked this conversation as resolved.
Outdated
|
||
|
|
||
| # References | ||
| - **Deep Dive into Shims**: See the architectural choices for the shim in [destructuring-shim.md](references/destructuring-shim.md). | ||
| - **Function Name Mapping**: See the V1 vs V2 function signature mapping table in [signature-mapping.md](references/signature-mapping.md). | ||
45 changes: 45 additions & 0 deletions
45
skills/firebase-v1-v2-migration/references/destructuring-shim.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # Architectural Deep Dive: Destructuring Compatibility Shim | ||
|
|
||
| The Destructuring Compatibility Shim is a **Zero-Touch Logic Migration** pattern. It allows you to upgrade a function's infrastructure to V2 (and take advantage of GCF 2nd Gen runtimes) without rewriting any of your internal business logic. | ||
|
|
||
| --- | ||
|
|
||
| ## 🛠️ How it Works | ||
|
|
||
| When you migrate a V1 function to V2, the signature changes from two parameters `(data, context)` to a single `CloudEvent` object. | ||
|
|
||
| Instead of manually rewriting all usages of `context.params` or `message.json` inside the function, you use JavaScript's **Object Destructuring** in the signature. | ||
|
|
||
| ### Example Transformation | ||
|
|
||
| #### Step 1: Legacy V1 | ||
|
|
||
| ```typescript | ||
| export const processOrder = functions.pubsub.topic("orders").onPublish((message, context) => { | ||
| const orderId = message.json.id; | ||
| console.log(`Processing order ${orderId} at ${context.timestamp}`); | ||
| }); | ||
| ``` | ||
|
|
||
| #### Step 2: Modern V2 + Shim | ||
|
|
||
| We change the trigger to `onMessagePublished`, and instead of accepting `event`, we destructure `{ message, context }` directly: | ||
|
|
||
| ```typescript | ||
| export const processOrder = onMessagePublished("orders", ({ message, context }) => { | ||
| const orderId = message.json.id; // Legacy logic remains untouched! | ||
| console.log(`Processing order ${orderId} at ${context.timestamp}`); | ||
| }); | ||
| ``` | ||
|
|
||
| ### 🧠 Why This Works | ||
|
|
||
| The Firebase Functions SDK has been updated to provide **Lazy Getters** on the `CloudEvent` object for standard event triggers. When you attempt to destructure `{ message, context }` from the event, the SDK transparently maps the V2 event properties back into V1-compatible objects on the fly! | ||
|
|
||
| --- | ||
|
|
||
| ## 🛡️ Best Practices for AI Agents | ||
|
|
||
| 1. **Do NOT attempt to rewrite variable access inside the body.** It is error-prone and time-consuming. | ||
| 2. **Rely on the shim by default.** Only attempt a pure V2 rewrite if the user explicitly asks for "clean-room" modernization. | ||
| 3. **Always type-check (`tsc`) after the rewrite.** If the types are wrong, the shim might not be fully supported for that specific provider yet! |
27 changes: 27 additions & 0 deletions
27
skills/firebase-v1-v2-migration/references/signature-mapping.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Firebase Functions V1 vs V2 Function Mapping | ||
|
|
||
| This reference table maps legacy V1 functions to their modern V2 equivalents. Use this table to find the correct V2 function names when migrating. | ||
|
|
||
| | Category | V1 Function | V2 Function | Status | Notes | | ||
| | :--- | :--- | :--- | :--- | :--- | | ||
| | **Auth** | `auth.user().beforeSignIn()` | `identity.beforeUserSignedIn()` | **Available** | Renamed to `beforeUserSignedIn`. | | ||
| | **Auth** | `auth.user().beforeCreate()` | `identity.beforeUserCreated()` | **Available** | | | ||
| | **Auth** | `auth.user().beforeEmail()` | `identity.beforeEmailSent()` | **Available** | Renamed to `beforeEmailSent`. | | ||
| | **Auth** | `auth.user().beforeSms()` | `identity.beforeSmsSent()` | **Available** | | | ||
| | **Database** | `database.ref().onWrite()` | `database.onValueWritten()` | **Available** | | | ||
| | **Database** | `database.ref().onCreate()` | `database.onValueCreated()` | **Available** | | | ||
| | **Database** | `database.ref().onUpdate()` | `database.onValueUpdated()` | **Available** | | | ||
| | **Database** | `database.ref().onDelete()` | `database.onValueDeleted()` | **Available** | | | ||
| | **Firestore** | `firestore.document().onWrite()` | `firestore.onDocumentWritten()` | **Available** | | | ||
| | **Firestore** | `firestore.document().onCreate()` | `firestore.onDocumentCreated()` | **Available** | | | ||
| | **Firestore** | `firestore.document().onUpdate()` | `firestore.onDocumentUpdated()` | **Available** | | | ||
| | **Firestore** | `firestore.document().onDelete()` | `firestore.onDocumentDeleted()` | **Available** | | | ||
| | **Pub/Sub** | `pubsub.topic().onPublish()` | `pubsub.onMessagePublished()` | **Available** | | | ||
| | **Pub/Sub** | `pubsub.schedule().onRun()` | `scheduler.onSchedule()` | **Available** | Moved to `scheduler` namespace. | | ||
| | **Storage** | `storage.object().onArchive()` | `storage.onObjectArchived()` | **Available** | | | ||
| | **Storage** | `storage.object().onDelete()` | `storage.onObjectDeleted()` | **Available** | | | ||
| | **Storage** | `storage.object().onFinalize()` | `storage.onObjectFinalized()` | **Available** | | | ||
| | **Storage** | `storage.object().onMetadataUpdate()` | `storage.onObjectMetadataUpdated()` | **Available** | | | ||
| | **HTTPS** | `https.onRequest()` | `https.onRequest()` | **Both** | Same name, different module. | | ||
| | **HTTPS** | `https.onCall()` | `https.onCall()` | **Both** | Different parameter type (`CallableRequest`). | | ||
|
shettyvarun268 marked this conversation as resolved.
Outdated
|
||
| | **Tasks** | `tasks.taskQueue().onDispatch()` | `tasks.onTaskDispatched()` | **Available** | | | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.