dreamcontext 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +523 -0
- package/agents/dreamcontext-explore.md +137 -0
- package/agents/dreamcontext-initializer.md +169 -0
- package/agents/sleep-product.md +268 -0
- package/agents/sleep-state.md +270 -0
- package/agents/sleep-tasks.md +134 -0
- package/dist/agents/dreamcontext-explore.md +137 -0
- package/dist/agents/dreamcontext-initializer.md +169 -0
- package/dist/agents/sleep-product.md +268 -0
- package/dist/agents/sleep-state.md +270 -0
- package/dist/agents/sleep-tasks.md +134 -0
- package/dist/dashboard/assets/BrainCanvas3D-BLJ4_SqE.js +5126 -0
- package/dist/dashboard/assets/_baseUniq-DpaDAx_H.js +1 -0
- package/dist/dashboard/assets/arc-JvK3Ik1p.js +1 -0
- package/dist/dashboard/assets/architectureDiagram-Q4EWVU46-CCvw4XFg.js +36 -0
- package/dist/dashboard/assets/blockDiagram-DXYQGD6D-DMobz1n7.js +132 -0
- package/dist/dashboard/assets/c4Diagram-AHTNJAMY-FwcHT5er.js +10 -0
- package/dist/dashboard/assets/channel-D6954IHZ.js +1 -0
- package/dist/dashboard/assets/chunk-4BX2VUAB-B5kYwmBa.js +1 -0
- package/dist/dashboard/assets/chunk-4TB4RGXK-0ot1eS0J.js +206 -0
- package/dist/dashboard/assets/chunk-55IACEB6-24ngcLgH.js +1 -0
- package/dist/dashboard/assets/chunk-EDXVE4YY-DATt1OUl.js +1 -0
- package/dist/dashboard/assets/chunk-FMBD7UC4-BprbGSJw.js +15 -0
- package/dist/dashboard/assets/chunk-OYMX7WX6-CJJhpKWP.js +231 -0
- package/dist/dashboard/assets/chunk-QZHKN3VN-Cisp65Vq.js +1 -0
- package/dist/dashboard/assets/chunk-YZCP3GAM-DtMk33tU.js +1 -0
- package/dist/dashboard/assets/classDiagram-6PBFFD2Q-Bk4KDqBj.js +1 -0
- package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-Bk4KDqBj.js +1 -0
- package/dist/dashboard/assets/clone-C9Yhti5q.js +1 -0
- package/dist/dashboard/assets/cose-bilkent-S5V4N54A-BxYomDLe.js +1 -0
- package/dist/dashboard/assets/cytoscape.esm-D_LviqZs.js +331 -0
- package/dist/dashboard/assets/dagre-KV5264BT-CsX1ZayG.js +4 -0
- package/dist/dashboard/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/dashboard/assets/diagram-5BDNPKRD-B2G4mPPw.js +10 -0
- package/dist/dashboard/assets/diagram-G4DWMVQ6-C8nxN9ZB.js +24 -0
- package/dist/dashboard/assets/diagram-MMDJMWI5-DaYymOrR.js +43 -0
- package/dist/dashboard/assets/diagram-TYMM5635-BpiYFv-I.js +24 -0
- package/dist/dashboard/assets/erDiagram-SMLLAGMA-C6pE7F61.js +85 -0
- package/dist/dashboard/assets/flowDiagram-DWJPFMVM-jdNEPVFq.js +162 -0
- package/dist/dashboard/assets/ganttDiagram-T4ZO3ILL-C8GoRj1C.js +292 -0
- package/dist/dashboard/assets/gitGraphDiagram-UUTBAWPF-SiRn7RJ8.js +106 -0
- package/dist/dashboard/assets/graph-9wbTW7ld.js +1 -0
- package/dist/dashboard/assets/index-BHp63EMw.js +475 -0
- package/dist/dashboard/assets/index-CdnDt_7U.css +1 -0
- package/dist/dashboard/assets/infoDiagram-42DDH7IO-DcDC8M1a.js +2 -0
- package/dist/dashboard/assets/ishikawaDiagram-UXIWVN3A-UjyrPeaS.js +70 -0
- package/dist/dashboard/assets/journeyDiagram-VCZTEJTY-CXJPYMxN.js +139 -0
- package/dist/dashboard/assets/kanban-definition-6JOO6SKY-Cm1n9eat.js +89 -0
- package/dist/dashboard/assets/katex-DkKDou_j.js +257 -0
- package/dist/dashboard/assets/layout-w8zmQGXp.js +1 -0
- package/dist/dashboard/assets/linear-CMNvIisH.js +1 -0
- package/dist/dashboard/assets/min-BqXwiqEr.js +1 -0
- package/dist/dashboard/assets/mindmap-definition-QFDTVHPH-tksxnjhx.js +96 -0
- package/dist/dashboard/assets/pieDiagram-DEJITSTG-lIVvnPyq.js +30 -0
- package/dist/dashboard/assets/quadrantDiagram-34T5L4WZ-DSMB57t5.js +7 -0
- package/dist/dashboard/assets/requirementDiagram-MS252O5E-NG99tgmc.js +84 -0
- package/dist/dashboard/assets/sankeyDiagram-XADWPNL6-C6EkbQKo.js +10 -0
- package/dist/dashboard/assets/sequenceDiagram-FGHM5R23-ASU7Zp6_.js +157 -0
- package/dist/dashboard/assets/stateDiagram-FHFEXIEX-DHklUzce.js +1 -0
- package/dist/dashboard/assets/stateDiagram-v2-QKLJ7IA2-BZXFb2Fh.js +1 -0
- package/dist/dashboard/assets/timeline-definition-GMOUNBTQ-B37xNhjS.js +120 -0
- package/dist/dashboard/assets/vennDiagram-DHZGUBPP-D28OvWbm.js +34 -0
- package/dist/dashboard/assets/wardley-RL74JXVD-BQdaLyVb.js +162 -0
- package/dist/dashboard/assets/wardleyDiagram-NUSXRM2D-D0vChrnT.js +20 -0
- package/dist/dashboard/assets/xychartDiagram-5P7HB3ND-BzSx7EpJ.js +7 -0
- package/dist/dashboard/favicon.svg +14 -0
- package/dist/dashboard/index.html +18 -0
- package/dist/hooks/marketing-binary-guard.sh +18 -0
- package/dist/index.js +15881 -0
- package/dist/skill-packs/agents/biv-customer-analyst.md +140 -0
- package/dist/skill-packs/agents/biv-decision-gate.md +147 -0
- package/dist/skill-packs/agents/biv-financial-analyst.md +128 -0
- package/dist/skill-packs/agents/biv-market-analyst.md +103 -0
- package/dist/skill-packs/agents/biv-researcher.md +140 -0
- package/dist/skill-packs/agents/biv-strategist.md +164 -0
- package/dist/skill-packs/agents/council-persona.md +142 -0
- package/dist/skill-packs/agents/council-synthesizer.md +208 -0
- package/dist/skill-packs/agents/discover-brand.md +216 -0
- package/dist/skill-packs/agents/goal-implementer.md +70 -0
- package/dist/skill-packs/agents/goal-plan-reviewer.md +68 -0
- package/dist/skill-packs/agents/goal-planner.md +75 -0
- package/dist/skill-packs/agents/goal-validator.md +68 -0
- package/dist/skill-packs/agents/marketing-creative.md +85 -0
- package/dist/skill-packs/agents/marketing-monitor.md +143 -0
- package/dist/skill-packs/agents/marketing-strategy.md +139 -0
- package/dist/skill-packs/agents/review-cloud-functions.md +158 -0
- package/dist/skill-packs/agents/review-edge-cases.md +147 -0
- package/dist/skill-packs/agents/review-frontend.md +134 -0
- package/dist/skill-packs/agents/review-router.md +165 -0
- package/dist/skill-packs/agents/review-security.md +139 -0
- package/dist/skill-packs/agents/reviewer.md +152 -0
- package/dist/skill-packs/brand-voice/SKILL.md +115 -0
- package/dist/skill-packs/brand-voice/discover-brand.md +126 -0
- package/dist/skill-packs/brand-voice/guideline-generation.md +154 -0
- package/dist/skill-packs/brand-voice/references/before-after-examples.md +194 -0
- package/dist/skill-packs/brand-voice/references/confidence-scoring.md +128 -0
- package/dist/skill-packs/brand-voice/references/guideline-template.md +241 -0
- package/dist/skill-packs/brand-voice/references/search-strategies.md +271 -0
- package/dist/skill-packs/brand-voice/references/source-ranking.md +248 -0
- package/dist/skill-packs/brand-voice/references/voice-constant-tone-flexes.md +115 -0
- package/dist/skill-packs/business-idea-discovery/SKILL.md +452 -0
- package/dist/skill-packs/business-idea-validation/SKILL.md +209 -0
- package/dist/skill-packs/business-idea-validation/stage-definitions.md +658 -0
- package/dist/skill-packs/catalog.json +657 -0
- package/dist/skill-packs/council/SKILL.md +134 -0
- package/dist/skill-packs/council/debate-protocol.md +90 -0
- package/dist/skill-packs/design/SKILL.md +301 -0
- package/dist/skill-packs/design/design-mobile.md +207 -0
- package/dist/skill-packs/design/design-web.md +148 -0
- package/dist/skill-packs/design/frontend-principles.md +157 -0
- package/dist/skill-packs/design/onboarding-design.md +230 -0
- package/dist/skill-packs/engineering/SKILL.md +155 -0
- package/dist/skill-packs/engineering/backend-principles.md +233 -0
- package/dist/skill-packs/engineering/firebase-cloud-functions/SKILL.md +44 -0
- package/dist/skill-packs/engineering/firebase-cloud-functions/references/gen_comparison.md +45 -0
- package/dist/skill-packs/engineering/firebase-cloud-functions/references/idempotency.md +145 -0
- package/dist/skill-packs/engineering/firebase-cloud-functions/references/local_testing.md +218 -0
- package/dist/skill-packs/engineering/firebase-cloud-functions/references/scaling.md +128 -0
- package/dist/skill-packs/engineering/firebase-cloud-functions/references/secrets.md +70 -0
- package/dist/skill-packs/engineering/firebase-cloud-functions/references/triggers_and_deployment.md +139 -0
- package/dist/skill-packs/engineering/firebase-firestore/SKILL.md +50 -0
- package/dist/skill-packs/engineering/firebase-firestore/references/indexes.md +96 -0
- package/dist/skill-packs/engineering/firebase-firestore/references/provisioning.md +101 -0
- package/dist/skill-packs/engineering/firebase-firestore/references/query_mechanics.md +182 -0
- package/dist/skill-packs/engineering/firebase-firestore/references/security_rules.md +299 -0
- package/dist/skill-packs/engineering/firebase-firestore/references/web_sdk_usage.md +265 -0
- package/dist/skill-packs/engineering/web-app-frontend.md +187 -0
- package/dist/skill-packs/goal-skill/SKILL.md +203 -0
- package/dist/skill-packs/growth/SKILL.md +480 -0
- package/dist/skill-packs/growth/lean-analytics-experiments.md +341 -0
- package/dist/skill-packs/growth/lean-analytics-metrics.md +295 -0
- package/dist/skill-packs/growth/performance-marketing.md +337 -0
- package/dist/skill-packs/meta-marketing/SKILL.md +423 -0
- package/dist/skill-packs/meta-marketing/account-ops.md +190 -0
- package/dist/skill-packs/meta-marketing/api-reference.md +535 -0
- package/dist/skill-packs/meta-marketing/copy-formulas.md +123 -0
- package/dist/skill-packs/meta-marketing/council-personas/creative-director.md +76 -0
- package/dist/skill-packs/meta-marketing/council-personas/performance-monitor.md +71 -0
- package/dist/skill-packs/meta-marketing/council-personas/risk-officer.md +79 -0
- package/dist/skill-packs/meta-marketing/council-personas/strategy-optimizer.md +76 -0
- package/dist/skill-packs/meta-marketing/creative-frameworks.md +176 -0
- package/dist/skill-packs/meta-marketing/mistakes.md +154 -0
- package/dist/skill-packs/meta-marketing/platform-state.md +63 -0
- package/dist/skill-packs/multi-review/REVIEWER_SHARED.md +143 -0
- package/dist/skill-packs/multi-review/SKILL.md +182 -0
- package/dist/skill-packs/system-prompts/SKILL.md +472 -0
- package/dist/templates/AGENTS.md +84 -0
- package/dist/templates/CLAUDE.md +84 -0
- package/dist/templates/council-debate.md +20 -0
- package/dist/templates/council-final-report.md +34 -0
- package/dist/templates/council-persona.md +10 -0
- package/dist/templates/council-report.md +6 -0
- package/dist/templates/feature.md +38 -0
- package/dist/templates/init/0.soul.md +33 -0
- package/dist/templates/init/1.user.md +29 -0
- package/dist/templates/init/2.memory.md +21 -0
- package/dist/templates/init/3.style_guide_and_branding.md +18 -0
- package/dist/templates/init/4.tech_stack.md +22 -0
- package/dist/templates/init/CHANGELOG.json +1 -0
- package/dist/templates/init/RELEASES.json +1 -0
- package/dist/templates/init/data-structures/default.md +35 -0
- package/dist/templates/knowledge.md +10 -0
- package/dist/templates/obsidian/app.json +15 -0
- package/dist/templates/obsidian/appearance.json +4 -0
- package/dist/templates/obsidian/graph.json +58 -0
- package/dist/templates/task.md +70 -0
- package/install.sh +73 -0
- package/package.json +58 -0
- package/skill/SKILL.md +529 -0
- package/skill-packs/agents/biv-customer-analyst.md +140 -0
- package/skill-packs/agents/biv-decision-gate.md +147 -0
- package/skill-packs/agents/biv-financial-analyst.md +128 -0
- package/skill-packs/agents/biv-market-analyst.md +103 -0
- package/skill-packs/agents/biv-researcher.md +140 -0
- package/skill-packs/agents/biv-strategist.md +164 -0
- package/skill-packs/agents/council-persona.md +142 -0
- package/skill-packs/agents/council-synthesizer.md +208 -0
- package/skill-packs/agents/discover-brand.md +216 -0
- package/skill-packs/agents/goal-implementer.md +70 -0
- package/skill-packs/agents/goal-plan-reviewer.md +68 -0
- package/skill-packs/agents/goal-planner.md +75 -0
- package/skill-packs/agents/goal-validator.md +68 -0
- package/skill-packs/agents/marketing-creative.md +85 -0
- package/skill-packs/agents/marketing-monitor.md +143 -0
- package/skill-packs/agents/marketing-strategy.md +139 -0
- package/skill-packs/agents/review-cloud-functions.md +158 -0
- package/skill-packs/agents/review-edge-cases.md +147 -0
- package/skill-packs/agents/review-frontend.md +134 -0
- package/skill-packs/agents/review-router.md +165 -0
- package/skill-packs/agents/review-security.md +139 -0
- package/skill-packs/agents/reviewer.md +152 -0
- package/skill-packs/brand-voice/SKILL.md +115 -0
- package/skill-packs/brand-voice/discover-brand.md +126 -0
- package/skill-packs/brand-voice/guideline-generation.md +154 -0
- package/skill-packs/brand-voice/references/before-after-examples.md +194 -0
- package/skill-packs/brand-voice/references/confidence-scoring.md +128 -0
- package/skill-packs/brand-voice/references/guideline-template.md +241 -0
- package/skill-packs/brand-voice/references/search-strategies.md +271 -0
- package/skill-packs/brand-voice/references/source-ranking.md +248 -0
- package/skill-packs/brand-voice/references/voice-constant-tone-flexes.md +115 -0
- package/skill-packs/business-idea-discovery/SKILL.md +452 -0
- package/skill-packs/business-idea-validation/SKILL.md +209 -0
- package/skill-packs/business-idea-validation/stage-definitions.md +658 -0
- package/skill-packs/catalog.json +657 -0
- package/skill-packs/council/SKILL.md +134 -0
- package/skill-packs/council/debate-protocol.md +90 -0
- package/skill-packs/design/SKILL.md +301 -0
- package/skill-packs/design/design-mobile.md +207 -0
- package/skill-packs/design/design-web.md +148 -0
- package/skill-packs/design/frontend-principles.md +157 -0
- package/skill-packs/design/onboarding-design.md +230 -0
- package/skill-packs/engineering/SKILL.md +155 -0
- package/skill-packs/engineering/backend-principles.md +233 -0
- package/skill-packs/engineering/firebase-cloud-functions/SKILL.md +44 -0
- package/skill-packs/engineering/firebase-cloud-functions/references/gen_comparison.md +45 -0
- package/skill-packs/engineering/firebase-cloud-functions/references/idempotency.md +145 -0
- package/skill-packs/engineering/firebase-cloud-functions/references/local_testing.md +218 -0
- package/skill-packs/engineering/firebase-cloud-functions/references/scaling.md +128 -0
- package/skill-packs/engineering/firebase-cloud-functions/references/secrets.md +70 -0
- package/skill-packs/engineering/firebase-cloud-functions/references/triggers_and_deployment.md +139 -0
- package/skill-packs/engineering/firebase-firestore/SKILL.md +50 -0
- package/skill-packs/engineering/firebase-firestore/references/indexes.md +96 -0
- package/skill-packs/engineering/firebase-firestore/references/provisioning.md +101 -0
- package/skill-packs/engineering/firebase-firestore/references/query_mechanics.md +182 -0
- package/skill-packs/engineering/firebase-firestore/references/security_rules.md +299 -0
- package/skill-packs/engineering/firebase-firestore/references/web_sdk_usage.md +265 -0
- package/skill-packs/engineering/web-app-frontend.md +187 -0
- package/skill-packs/goal-skill/SKILL.md +203 -0
- package/skill-packs/growth/SKILL.md +480 -0
- package/skill-packs/growth/lean-analytics-experiments.md +341 -0
- package/skill-packs/growth/lean-analytics-metrics.md +295 -0
- package/skill-packs/growth/performance-marketing.md +337 -0
- package/skill-packs/meta-marketing/SKILL.md +423 -0
- package/skill-packs/meta-marketing/account-ops.md +190 -0
- package/skill-packs/meta-marketing/api-reference.md +535 -0
- package/skill-packs/meta-marketing/copy-formulas.md +123 -0
- package/skill-packs/meta-marketing/council-personas/creative-director.md +76 -0
- package/skill-packs/meta-marketing/council-personas/performance-monitor.md +71 -0
- package/skill-packs/meta-marketing/council-personas/risk-officer.md +79 -0
- package/skill-packs/meta-marketing/council-personas/strategy-optimizer.md +76 -0
- package/skill-packs/meta-marketing/creative-frameworks.md +176 -0
- package/skill-packs/meta-marketing/mistakes.md +154 -0
- package/skill-packs/meta-marketing/platform-state.md +63 -0
- package/skill-packs/multi-review/REVIEWER_SHARED.md +143 -0
- package/skill-packs/multi-review/SKILL.md +182 -0
- package/skill-packs/system-prompts/SKILL.md +472 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# 1st Gen vs 2nd Gen Comparison
|
|
2
|
+
|
|
3
|
+
**2nd gen is mandatory for all new functions.** 1st gen is legacy only.
|
|
4
|
+
|
|
5
|
+
## Comparison Table
|
|
6
|
+
|
|
7
|
+
| Feature | 1st Gen | 2nd Gen (Cloud Run) |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Infrastructure | Legacy Firebase Runtime | Cloud Run + Eventarc (90+ event sources) |
|
|
10
|
+
| HTTP Timeout | 9 minutes | **60 minutes** |
|
|
11
|
+
| Event Timeout | 540s | 540s (scheduled/task queue: 1800s) |
|
|
12
|
+
| Max Instance Size | 8 GiB RAM / 2 vCPU | **32 GiB RAM / 4 vCPU** (16 GiB recommended) |
|
|
13
|
+
| Concurrency per instance | 1 request | **1–1000** (default 80) |
|
|
14
|
+
| Min Instances | Available | Available + **CPU scaling** |
|
|
15
|
+
| Service Account | App Engine default | Compute Engine default (more secure) |
|
|
16
|
+
| Trigger Support | Limited Firebase events | **All Eventarc** + Pub/Sub + custom |
|
|
17
|
+
| Image Registry | Container/Artifact Registry | **Artifact Registry only** |
|
|
18
|
+
| Traffic Splitting | No | Yes (revision rollback) |
|
|
19
|
+
| Retry Window | 7 days | **24 hours** |
|
|
20
|
+
|
|
21
|
+
## Supported Runtimes (March 2026)
|
|
22
|
+
|
|
23
|
+
- **Node.js**: 22 (recommended), 20, 18 (deprecated)
|
|
24
|
+
- **Python**: 3.11+ (`firebase-functions` Python SDK)
|
|
25
|
+
- **TypeScript**: Native (ESM/CommonJS)
|
|
26
|
+
|
|
27
|
+
## Import Pattern
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
// 2nd gen (CORRECT)
|
|
31
|
+
const { onRequest, onCall } = require("firebase-functions/v2/https");
|
|
32
|
+
const { onDocumentCreated, onDocumentUpdated } = require("firebase-functions/v2/firestore");
|
|
33
|
+
|
|
34
|
+
// 1st gen (LEGACY — do not use in new code)
|
|
35
|
+
const functions = require("firebase-functions");
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Migration Rule
|
|
39
|
+
|
|
40
|
+
If agent encounters 1st gen code:
|
|
41
|
+
1. Replace `functions.https.onRequest` → `onRequest` from `firebase-functions/v2/https`
|
|
42
|
+
2. Replace `functions.firestore.document().onUpdate` → `onDocumentUpdated` from `firebase-functions/v2/firestore`
|
|
43
|
+
3. Replace `.runWith({ failurePolicy: true })` → `{ retry: true }` in options
|
|
44
|
+
4. Replace `functions.config()` → `defineSecret()` / `defineString()`
|
|
45
|
+
5. Add `concurrency` and `minInstances` to options
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Idempotency & Infinite Loop Prevention
|
|
2
|
+
|
|
3
|
+
**THE most critical reference in this skill.** Firestore trigger loops and non-idempotent retries cause billing explosions ($1000s+), quota exhaustion, and data corruption.
|
|
4
|
+
|
|
5
|
+
## 1. At-Least-Once Delivery
|
|
6
|
+
|
|
7
|
+
Firebase event triggers (Firestore, Pub/Sub, Storage, etc.) do NOT guarantee exactly-once delivery. The same event CAN fire multiple times (retry, duplicate delivery).
|
|
8
|
+
|
|
9
|
+
**Idempotency = same input → same output, no extra side effects on repeat calls.**
|
|
10
|
+
|
|
11
|
+
If a function is NOT idempotent + retry is enabled → duplicated writes, double charges, duplicate emails, infinite loops.
|
|
12
|
+
|
|
13
|
+
## 2. Infinite Loop — The #1 Danger
|
|
14
|
+
|
|
15
|
+
**Root cause**: Firestore `onUpdate`/`onWrite` trigger writes to the SAME document → triggers itself → infinite loop.
|
|
16
|
+
|
|
17
|
+
### NEVER DO THIS
|
|
18
|
+
```js
|
|
19
|
+
// DANGEROUS — infinite loop!
|
|
20
|
+
exports.badFunction = onDocumentUpdated("users/{userId}", (event) => {
|
|
21
|
+
return event.data.after.ref.update({ lastUpdated: new Date() });
|
|
22
|
+
// ↑ This update triggers onDocumentUpdated again → loop forever
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Real-world cost: A developer in 2024 got an **$8,000 bill** from a timestamp update loop.
|
|
27
|
+
|
|
28
|
+
## 3. Three-Layer Guard System (ALL REQUIRED for retry-enabled functions)
|
|
29
|
+
|
|
30
|
+
### Layer 1: Event Age Check (drops stale retries)
|
|
31
|
+
```js
|
|
32
|
+
const eventAgeMs = Date.now() - Date.parse(event.time);
|
|
33
|
+
if (eventAgeMs > 10000) { // 10 seconds
|
|
34
|
+
console.log("Stale event dropped");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Layer 2: Before/After Comparison (prevents self-trigger loops)
|
|
40
|
+
```js
|
|
41
|
+
exports.safeCounter = onDocumentUpdated("users/{userId}", (event) => {
|
|
42
|
+
const before = event.data.before.data();
|
|
43
|
+
const after = event.data.after.data();
|
|
44
|
+
|
|
45
|
+
// Only run if the field we care about actually changed
|
|
46
|
+
if (before.name === after.name) {
|
|
47
|
+
console.log("No relevant change → loop prevented");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return event.data.after.ref.set({
|
|
52
|
+
name_change_count: (after.name_change_count || 0) + 1
|
|
53
|
+
}, { merge: true });
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Layer 3: Idempotency Key + Transaction (guarantees exactly-once processing)
|
|
58
|
+
```js
|
|
59
|
+
exports.processOrder = onDocumentCreated(
|
|
60
|
+
{ document: "orders/{orderId}", retry: true },
|
|
61
|
+
async (event) => {
|
|
62
|
+
const eventId = event.id;
|
|
63
|
+
const processedRef = db.collection("processedEvents").doc(eventId);
|
|
64
|
+
|
|
65
|
+
await db.runTransaction(async (t) => {
|
|
66
|
+
const snap = await t.get(processedRef);
|
|
67
|
+
if (snap.exists) return; // Already processed → idempotent skip
|
|
68
|
+
|
|
69
|
+
// Do the work
|
|
70
|
+
await event.data.ref.update({ status: "processed" });
|
|
71
|
+
t.set(processedRef, { done: true, processedAt: FieldValue.serverTimestamp() });
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Python Example (same guards)
|
|
78
|
+
```python
|
|
79
|
+
@on_document_updated(document="users/{userId}")
|
|
80
|
+
def safe_counter(event):
|
|
81
|
+
before = event.data.before.to_dict()
|
|
82
|
+
after = event.data.after.to_dict()
|
|
83
|
+
|
|
84
|
+
if before.get("name") == after.get("name"):
|
|
85
|
+
return # No change → prevent loop
|
|
86
|
+
|
|
87
|
+
event.data.after.reference.update({
|
|
88
|
+
"name_change_count": after.get("name_change_count", 0) + 1
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 4. Alternative Loop Prevention Patterns
|
|
93
|
+
|
|
94
|
+
### Processed Flag / Timestamp
|
|
95
|
+
```js
|
|
96
|
+
const after = event.data.after.data();
|
|
97
|
+
const before = event.data.before.data();
|
|
98
|
+
if (after.processedAt && after.processedAt > before.processedAt) return;
|
|
99
|
+
await docRef.update({ processedAt: FieldValue.serverTimestamp() });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Separate Collection
|
|
103
|
+
Write trigger output to a different collection instead of the same document:
|
|
104
|
+
- Trigger on `users/{userId}` → write to `userEvents/{eventId}`
|
|
105
|
+
- Or use subcollection: `users/{userId}/processed/{eventId}`
|
|
106
|
+
|
|
107
|
+
## 5. External API Idempotency
|
|
108
|
+
|
|
109
|
+
For external services (Stripe, SendGrid, etc.), use `event.id` as the idempotency key:
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
const stripe = require("stripe")(stripeKey.value());
|
|
113
|
+
await stripe.charges.create({
|
|
114
|
+
amount: 1000,
|
|
115
|
+
currency: "usd",
|
|
116
|
+
source: token,
|
|
117
|
+
}, {
|
|
118
|
+
idempotencyKey: event.id // Stripe deduplicates based on this
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 6. Retry Configuration
|
|
123
|
+
|
|
124
|
+
### 2nd Gen (recommended)
|
|
125
|
+
```js
|
|
126
|
+
{ retry: true } // 24-hour retry window
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 1st Gen (legacy)
|
|
130
|
+
```js
|
|
131
|
+
.runWith({ failurePolicy: true }) // 7-day retry window
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**RULE**: NEVER enable retry without all three guard layers. Retry + loop = 24 hours (or 7 days in 1st gen) of continuous invocations.
|
|
135
|
+
|
|
136
|
+
## 7. Decision Matrix
|
|
137
|
+
|
|
138
|
+
| Scenario | Required Guards |
|
|
139
|
+
|---|---|
|
|
140
|
+
| Firestore `onUpdate`/`onWrite` + no retry | Layer 2 (before/after) minimum |
|
|
141
|
+
| Firestore `onUpdate`/`onWrite` + retry | ALL THREE layers |
|
|
142
|
+
| Firestore `onCreate` + retry | Layer 1 (age) + Layer 3 (idempotency key) |
|
|
143
|
+
| HTTP / Callable | Standard HTTP idempotency (request dedup) |
|
|
144
|
+
| Pub/Sub + retry | Layer 1 + Layer 3 |
|
|
145
|
+
| External API call | Layer 3 + API-level idempotency key |
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Cloud Functions Local Testing – Emulator Suite Deep Dive
|
|
2
|
+
|
|
3
|
+
Test everything locally before deploying. Zero risk, zero cost.
|
|
4
|
+
|
|
5
|
+
## 1. Setup (One-time)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g firebase-tools@latest
|
|
9
|
+
firebase login
|
|
10
|
+
firebase init emulators
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requirements:
|
|
14
|
+
- `firebase-admin` >= 8.0.0
|
|
15
|
+
- `firebase-functions` >= 3.0.0 (v2 syntax for 2nd gen)
|
|
16
|
+
- Java 11+ (Firestore emulator requires JVM)
|
|
17
|
+
|
|
18
|
+
### firebase.json emulator config
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"emulators": {
|
|
22
|
+
"functions": { "port": 5001 },
|
|
23
|
+
"firestore": { "port": 8080 },
|
|
24
|
+
"auth": { "port": 9099 },
|
|
25
|
+
"storage": { "port": 9199 },
|
|
26
|
+
"pubsub": { "port": 8085 },
|
|
27
|
+
"eventarc": { "port": 9299 },
|
|
28
|
+
"ui": { "port": 4000 }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 2. Running the Emulator
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# All emulators (recommended)
|
|
37
|
+
firebase emulators:start
|
|
38
|
+
|
|
39
|
+
# Specific emulators
|
|
40
|
+
firebase emulators:start --only functions,firestore,auth
|
|
41
|
+
|
|
42
|
+
# Run tests then auto-shutdown
|
|
43
|
+
firebase emulators:exec "npm test" --only functions,firestore
|
|
44
|
+
|
|
45
|
+
# Debug mode (VS Code / Chrome DevTools breakpoints)
|
|
46
|
+
firebase emulators:start --inspect-functions
|
|
47
|
+
# → Open chrome://inspect to attach debugger
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Demo Project (safest — never touches production)
|
|
51
|
+
```bash
|
|
52
|
+
firebase use --add demo-myproject # demo- prefix is mandatory
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 3. Supported Function Types in Emulator
|
|
56
|
+
|
|
57
|
+
| Type | How to Test |
|
|
58
|
+
|---|---|
|
|
59
|
+
| HTTPS / Callable | `http://localhost:5001/<project>/<region>/<name>` |
|
|
60
|
+
| Firestore triggers | Write via Admin SDK or Emulator UI → trigger fires |
|
|
61
|
+
| Auth triggers | Create user via Admin SDK or Emulator UI |
|
|
62
|
+
| Storage triggers | Upload file via Emulator UI |
|
|
63
|
+
| Pub/Sub | Publish message via Admin SDK |
|
|
64
|
+
| Eventarc (2nd gen) | `firebase emulators:start --only functions,eventarc` |
|
|
65
|
+
| Alerts | Send synthetic alert from Emulator UI (Alerts tab) |
|
|
66
|
+
| Scheduled | NO native emulator support → test via manual HTTP trigger |
|
|
67
|
+
| Task Queue | Dispatch works, but rate limiting differs from production |
|
|
68
|
+
|
|
69
|
+
### 2nd Gen + Eventarc Setup
|
|
70
|
+
```bash
|
|
71
|
+
firebase emulators:start --only functions,eventarc
|
|
72
|
+
# EVENTARC_EMULATOR=localhost:9299 is set automatically
|
|
73
|
+
# Admin SDK captures events automatically
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 4. Connecting Client Apps to Emulator
|
|
77
|
+
|
|
78
|
+
### Web (Firebase v10+ Modular)
|
|
79
|
+
```js
|
|
80
|
+
import { getFunctions, connectFunctionsEmulator } from "firebase/functions";
|
|
81
|
+
const functions = getFunctions();
|
|
82
|
+
connectFunctionsEmulator(functions, "127.0.0.1", 5001);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Android (Kotlin)
|
|
86
|
+
```kotlin
|
|
87
|
+
Firebase.functions.useEmulator("10.0.2.2", 5001)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### iOS (Swift)
|
|
91
|
+
```swift
|
|
92
|
+
Functions.functions().useEmulator(withHost: "localhost", port: 5001)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
HTTPS functions: call `http://localhost:5001/...` directly.
|
|
96
|
+
|
|
97
|
+
## 5. Environment & Secrets in Emulator
|
|
98
|
+
|
|
99
|
+
### .env.local (highest priority, emulator-only)
|
|
100
|
+
```
|
|
101
|
+
# .env.local (gitignored, only used in emulator)
|
|
102
|
+
API_KEY=local-test-key
|
|
103
|
+
AUDIENCE=Local Humans
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Secrets
|
|
107
|
+
- Create `.secret.local` to override production secrets locally.
|
|
108
|
+
- Without `.secret.local`, emulator pulls from Secret Manager via ADC (Application Default Credentials).
|
|
109
|
+
- `.secret.local` takes priority.
|
|
110
|
+
|
|
111
|
+
### Legacy Runtime Config
|
|
112
|
+
```bash
|
|
113
|
+
firebase functions:config:get > .runtimeconfig.json
|
|
114
|
+
# Emulator reads this file automatically
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 6. Emulator UI (localhost:4000)
|
|
118
|
+
|
|
119
|
+
The most powerful debugging tool:
|
|
120
|
+
- **Logs** → real-time `console.log` / `console.error` output
|
|
121
|
+
- **Functions** → list of active triggers with execution details
|
|
122
|
+
- **Firestore / Auth / Storage** → modify data directly, triggers fire automatically
|
|
123
|
+
- **Alerts** → send synthetic alert events
|
|
124
|
+
- **Execution Details** → input/output payloads, runtime duration, error stacks
|
|
125
|
+
|
|
126
|
+
## 7. Debugging
|
|
127
|
+
|
|
128
|
+
### Terminal + Emulator UI
|
|
129
|
+
Both show logs simultaneously. `console.error` appears in red.
|
|
130
|
+
|
|
131
|
+
### VS Code Debugger
|
|
132
|
+
```bash
|
|
133
|
+
firebase emulators:start --inspect-functions
|
|
134
|
+
```
|
|
135
|
+
Then attach VS Code debugger or use `chrome://inspect`.
|
|
136
|
+
|
|
137
|
+
### Breakpoints
|
|
138
|
+
With `--inspect-functions`, set breakpoints in VS Code. Step through trigger execution line by line.
|
|
139
|
+
|
|
140
|
+
## 8. Local vs Production Differences
|
|
141
|
+
|
|
142
|
+
| Aspect | Local Emulator | Production (Cloud Run) | Test Strategy |
|
|
143
|
+
|---|---|---|---|
|
|
144
|
+
| Retries | NOT supported | 24-hour window (2nd gen) | Manually trigger same event 3-5x |
|
|
145
|
+
| Concurrency | Unlimited (local CPU) | 1–1000 per instance | Cannot test locally |
|
|
146
|
+
| Cold Start | None (always warm) | 500ms–5s possible | Test after real deploy |
|
|
147
|
+
| Timeout | `timeoutSeconds` honored | Same | Same code works |
|
|
148
|
+
| Memory/CPU | Unlimited (local machine) | 32 GiB / 4 vCPU max | Local test is valid |
|
|
149
|
+
| OS | Your machine (macOS/Windows) | Linux container | Bundle Linux binaries if needed |
|
|
150
|
+
| IAM | ADC (your credentials) | Service account | Test IAM in production |
|
|
151
|
+
| Networking | localhost only | Internet + VPC | Mock external APIs locally |
|
|
152
|
+
|
|
153
|
+
## 9. Idempotency & Loop Testing Protocol
|
|
154
|
+
|
|
155
|
+
Since retries don't work in the emulator, test idempotency manually:
|
|
156
|
+
|
|
157
|
+
1. **Trigger the same event 5 times** (via Emulator UI or Admin SDK script)
|
|
158
|
+
2. Verify `before/after` guard prevents re-processing
|
|
159
|
+
3. Verify `eventAgeMs` check would drop stale events (simulate with old timestamps)
|
|
160
|
+
4. Check `processedEvents` collection in emulator Firestore — should have exactly 1 entry per event
|
|
161
|
+
5. Verify no infinite loop: watch Emulator UI logs for recursive trigger patterns
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
// Test script: trigger same Firestore write 5 times
|
|
165
|
+
const admin = require("firebase-admin");
|
|
166
|
+
admin.initializeApp({ projectId: "demo-test" });
|
|
167
|
+
const db = admin.firestore();
|
|
168
|
+
db.settings({ host: "localhost:8080", ssl: false });
|
|
169
|
+
|
|
170
|
+
for (let i = 0; i < 5; i++) {
|
|
171
|
+
await db.doc("users/test-user").set({ name: "Test", iteration: i });
|
|
172
|
+
}
|
|
173
|
+
// Check: function should process only relevant changes, not loop
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## 10. Advanced Testing Patterns
|
|
177
|
+
|
|
178
|
+
### Unit Tests (Firebase Test SDK)
|
|
179
|
+
```bash
|
|
180
|
+
npm install --save-dev @firebase/rules-unit-testing
|
|
181
|
+
```
|
|
182
|
+
Use with Mocha or Jest for isolated function testing.
|
|
183
|
+
|
|
184
|
+
### Integration Tests with Auto-Shutdown
|
|
185
|
+
```bash
|
|
186
|
+
firebase emulators:exec "npm test" --only functions,firestore
|
|
187
|
+
# Starts emulators → runs tests → shuts down automatically
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Data Seeding
|
|
191
|
+
- Import/export Firestore data via Emulator UI
|
|
192
|
+
- Or seed programmatically with Admin SDK in test setup
|
|
193
|
+
|
|
194
|
+
### CI/CD Pipeline
|
|
195
|
+
```bash
|
|
196
|
+
# In CI (GitHub Actions, etc.)
|
|
197
|
+
firebase emulators:exec "npm test" --only functions,firestore
|
|
198
|
+
```
|
|
199
|
+
Java 11+ must be available in CI environment.
|
|
200
|
+
|
|
201
|
+
## 11. Agent Testing Checklist
|
|
202
|
+
|
|
203
|
+
Before considering any function "tested":
|
|
204
|
+
|
|
205
|
+
1. `firebase emulators:start --only functions,firestore,eventarc` running?
|
|
206
|
+
2. Client SDK has `connectFunctionsEmulator` / `useEmulator` call?
|
|
207
|
+
3. 2nd gen functions: Eventarc emulator included?
|
|
208
|
+
4. `.env.local` + `.secret.local` configured for local secrets?
|
|
209
|
+
5. Idempotency test: same event triggered 3+ times, no duplicates?
|
|
210
|
+
6. Loop guard test: `before/after` comparison verified in logs?
|
|
211
|
+
7. Emulator UI logs checked for unexpected re-triggers?
|
|
212
|
+
8. Production differences documented (retry, scaling, OS)?
|
|
213
|
+
9. `emulators:exec` used for CI/automated test runs?
|
|
214
|
+
|
|
215
|
+
### Prohibitions
|
|
216
|
+
- Deploying to production without local emulator testing
|
|
217
|
+
- Relying on production retries instead of testing idempotency locally
|
|
218
|
+
- Depending on local-only native commands (ImageMagick, etc.) without bundling for Linux
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Scaling, Concurrency & Cold Start
|
|
2
|
+
|
|
3
|
+
## Concurrency (2nd Gen's Biggest Advantage)
|
|
4
|
+
|
|
5
|
+
A single 2nd gen instance can handle **1–1000 concurrent requests** (default: 80).
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
exports.myFunc = onRequest({
|
|
9
|
+
concurrency: 500, // 500 simultaneous requests per instance
|
|
10
|
+
minInstances: 5, // 5 warm instances always ready
|
|
11
|
+
maxInstances: 100, // cap to prevent runaway scaling
|
|
12
|
+
memory: "1GiB",
|
|
13
|
+
cpu: 2,
|
|
14
|
+
}, (req, res) => { ... });
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Recommended Concurrency Values
|
|
18
|
+
|
|
19
|
+
| Function Type | Concurrency | Rationale |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| HTTP / Callable | >= 200 | High throughput, shared instance state |
|
|
22
|
+
| Firestore background trigger | >= 80 | Moderate parallelism |
|
|
23
|
+
| CPU-intensive (image processing) | 1–10 | Avoid resource contention |
|
|
24
|
+
| External API calls (rate-limited) | 10–50 | Respect downstream limits |
|
|
25
|
+
|
|
26
|
+
## Cold Start Prevention
|
|
27
|
+
|
|
28
|
+
Cold start = new instance spin-up. Can add 500ms–5s latency.
|
|
29
|
+
|
|
30
|
+
### minInstances (primary solution)
|
|
31
|
+
```js
|
|
32
|
+
{ minInstances: 1 } // At least 1 warm instance → cold start eliminated for most traffic
|
|
33
|
+
```
|
|
34
|
+
- `minInstances: 1` reduces cold starts by ~90%.
|
|
35
|
+
- `minInstances: 5` for high-traffic production functions.
|
|
36
|
+
- Cost: warm instances bill for idle time. Trade-off: latency vs cost.
|
|
37
|
+
|
|
38
|
+
### Global Variable Caching
|
|
39
|
+
```js
|
|
40
|
+
// Initialize ONCE, reuse across invocations on same instance
|
|
41
|
+
const admin = require("firebase-admin");
|
|
42
|
+
admin.initializeApp();
|
|
43
|
+
const db = admin.firestore();
|
|
44
|
+
|
|
45
|
+
// Heavy clients: cache at module level
|
|
46
|
+
let aiClient;
|
|
47
|
+
function getAiClient() {
|
|
48
|
+
if (!aiClient) aiClient = new SomeAiClient();
|
|
49
|
+
return aiClient;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### onInit() for Heavy Initialization (2nd gen)
|
|
54
|
+
```js
|
|
55
|
+
const { onInit } = require("firebase-functions/v2/core");
|
|
56
|
+
|
|
57
|
+
onInit(() => {
|
|
58
|
+
// Runs once per instance, before any request
|
|
59
|
+
// Use for GenAI client init, connection pools, etc.
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Background Activity — FORBIDDEN
|
|
64
|
+
|
|
65
|
+
NEVER start background work after sending a response:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
// WRONG — background activity breaks instance reuse
|
|
69
|
+
exports.bad = onRequest((req, res) => {
|
|
70
|
+
res.send("OK");
|
|
71
|
+
setTimeout(() => doSomething(), 5000); // ← NEVER DO THIS
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// CORRECT — finish all work before responding
|
|
75
|
+
exports.good = onRequest(async (req, res) => {
|
|
76
|
+
await doSomething();
|
|
77
|
+
res.send("OK");
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Runtime Options (Full Template)
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
const { setGlobalOptions } = require("firebase-functions/v2");
|
|
85
|
+
|
|
86
|
+
setGlobalOptions({
|
|
87
|
+
region: "us-central1",
|
|
88
|
+
memory: "512MiB",
|
|
89
|
+
cpu: 1,
|
|
90
|
+
concurrency: 200,
|
|
91
|
+
minInstances: 1,
|
|
92
|
+
maxInstances: 50,
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Per-function override:
|
|
97
|
+
```js
|
|
98
|
+
exports.heavyFunc = onRequest({
|
|
99
|
+
timeoutSeconds: 300,
|
|
100
|
+
memory: "4GiB",
|
|
101
|
+
cpu: 4,
|
|
102
|
+
concurrency: 10,
|
|
103
|
+
minInstances: 2,
|
|
104
|
+
maxInstances: 20,
|
|
105
|
+
serviceAccount: "my-sa@project.iam.gserviceaccount.com"
|
|
106
|
+
}, handler);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## CPU Scaling Option
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
// Use 1st gen CPU behavior (scales with memory)
|
|
113
|
+
setGlobalOptions({ cpu: "gcf_gen1" });
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Quotas & Limits (March 2026)
|
|
117
|
+
|
|
118
|
+
| Limit | 2nd Gen |
|
|
119
|
+
|---|---|
|
|
120
|
+
| Max memory | 32 GiB |
|
|
121
|
+
| Max vCPU | 4 |
|
|
122
|
+
| HTTP timeout | 60 minutes |
|
|
123
|
+
| Event timeout | 540s (scheduled: 1800s) |
|
|
124
|
+
| Concurrency per instance | 1000 |
|
|
125
|
+
| Function count | ~1000 (minus Cloud Run services) |
|
|
126
|
+
| Max deployment size | 100 MiB (compressed) |
|
|
127
|
+
|
|
128
|
+
Quota exceeded = HTTP 500 + function stops. Always set `maxInstances` to cap costs.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Secrets & Environment Configuration
|
|
2
|
+
|
|
3
|
+
## functions.config() is DEPRECATED
|
|
4
|
+
|
|
5
|
+
`functions.config()` is deprecated and will be **removed March 2027**. Agent MUST NOT use it.
|
|
6
|
+
|
|
7
|
+
## Correct Approach: Parameterized Config + Secret Manager
|
|
8
|
+
|
|
9
|
+
### Secrets (API keys, credentials)
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
const { defineSecret } = require("firebase-functions/params");
|
|
13
|
+
const apiKey = defineSecret("API_KEY");
|
|
14
|
+
const stripeKey = defineSecret("STRIPE_SECRET_KEY");
|
|
15
|
+
|
|
16
|
+
exports.myFunc = onRequest(
|
|
17
|
+
{ secrets: [apiKey, stripeKey] }, // Declare which secrets this function needs
|
|
18
|
+
(req, res) => {
|
|
19
|
+
const key = apiKey.value(); // Access at runtime
|
|
20
|
+
const stripe = require("stripe")(stripeKey.value());
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### CLI Commands
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
firebase functions:secrets:set API_KEY # Set a secret
|
|
29
|
+
firebase functions:secrets:access API_KEY # Read current value
|
|
30
|
+
firebase functions:secrets:destroy API_KEY # Delete
|
|
31
|
+
firebase functions:secrets:prune # Remove unused secrets
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Environment Variables (non-sensitive config)
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
const { defineString, defineInt } = require("firebase-functions/params");
|
|
38
|
+
|
|
39
|
+
const region = defineString("REGION", { default: "us-central1" });
|
|
40
|
+
const maxRetries = defineInt("MAX_RETRIES", { default: 3 });
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### .env Files (development only)
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
# .env (all environments)
|
|
47
|
+
REGION=us-central1
|
|
48
|
+
|
|
49
|
+
# .env.local (emulator only — gitignored)
|
|
50
|
+
API_KEY=test-key-123
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**NEVER commit `.env` files with real secrets to version control.**
|
|
54
|
+
|
|
55
|
+
## Secret Access Scope
|
|
56
|
+
|
|
57
|
+
- Secrets are only available to functions that declare them in `secrets: [...]`.
|
|
58
|
+
- Undeclared access → runtime error (value is empty).
|
|
59
|
+
- Security rules do NOT apply to secrets — they are Cloud-level access control.
|
|
60
|
+
|
|
61
|
+
## Service Account
|
|
62
|
+
|
|
63
|
+
2nd gen uses **Compute Engine default service account** (more restrictive than 1st gen's App Engine default).
|
|
64
|
+
|
|
65
|
+
Override per function:
|
|
66
|
+
```js
|
|
67
|
+
{
|
|
68
|
+
serviceAccount: "custom-sa@project.iam.gserviceaccount.com"
|
|
69
|
+
}
|
|
70
|
+
```
|