backend-manager 5.9.4 → 5.9.6
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/CLAUDE.md +6 -0
- package/package.json +8 -1
- package/src/cli/commands/install.js +4 -3
- package/src/cli/commands/setup-tests/backend-manager.js +2 -1
- package/src/cli/commands/setup-tests/firebase-admin.js +2 -1
- package/src/cli/commands/setup-tests/firebase-functions.js +2 -1
- package/src/cli/utils/safe-install.js +13 -0
- package/src/manager/routes/payments/cancel/post.js +22 -2
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/metadata.json +14 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/newsletter.html +486 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/newsletter.md +41 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/newsletter.mjml +97 -0
- package/{test/email/fixtures/clean.json → src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/structure.json} +16 -4
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-11T03-28-07/summary.md +1 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/metadata.json +14 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/newsletter.html +486 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/newsletter.md +41 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/newsletter.mjml +97 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/structure.json +42 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-00-28/summary.md +1 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/metadata.json +14 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/newsletter.html +486 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/newsletter.md +41 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/newsletter.mjml +97 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/structure.json +42 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-06-18T01-01-34/summary.md +1 -0
- package/src/test/fixtures/firebase-project/.temp/test-mode.json +6 -0
- package/src/test/fixtures/firebase-project/database-debug.log +12 -0
- package/src/test/fixtures/firebase-project/firestore-debug.log +136 -0
- package/src/test/fixtures/firebase-project/pubsub-debug.log +17 -0
- package/src/test/test-accounts.js +9 -0
- package/.codeclimate.yml +0 -32
- package/.nvmrc +0 -1
- package/CHANGELOG.md +0 -1432
- package/PROGRESS.md +0 -86
- package/TODO-2.md +0 -121
- package/TODO-CHARGEBLAST.md +0 -32
- package/TODO-WEBHOOK-KEY-LEGACY-REMOVAL.md +0 -15
- package/TODO-WEBHOOK-KEY-UPGRADE.md +0 -138
- package/TODO-email-auth.md +0 -14
- package/TODO.md +0 -187
- package/plans/mcp2.md +0 -247
- package/scripts/test-helper-providers.js +0 -162
- package/scripts/update-disposable-domains.js +0 -44
- package/templates/_.env +0 -42
- package/templates/_.gitignore +0 -60
- package/templates/backend-manager-config.json +0 -249
- package/templates/database.rules.json +0 -83
- package/templates/firebase.json +0 -66
- package/templates/firestore.indexes.json +0 -4
- package/templates/firestore.rules +0 -112
- package/templates/public/404.html +0 -26
- package/templates/public/index.html +0 -24
- package/templates/remoteconfig.template.json +0 -1
- package/templates/storage-lifecycle-config-1-day.json +0 -9
- package/templates/storage-lifecycle-config-30-days.json +0 -9
- package/templates/storage.rules +0 -8
- package/test/_init/accounts-validation.js +0 -58
- package/test/_legacy/ai/index.js +0 -231
- package/test/_legacy/ai/test.jpg +0 -0
- package/test/_legacy/ai/test.pdf +0 -0
- package/test/_legacy/index.js +0 -31
- package/test/_legacy/payment-resolver/chargebee/orders/refunded.json +0 -0
- package/test/_legacy/payment-resolver/chargebee/orders/unpaid.json +0 -98
- package/test/_legacy/payment-resolver/chargebee/subscriptions/active.json +0 -578
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-in-trial.json +0 -38
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-skipped-to-active.json +0 -135
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-active-to-cancelled.json +0 -42
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-active.json +0 -44
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-cancelled.json +0 -39
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-refund.json +0 -143
- package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-suspended.json +0 -48
- package/test/_legacy/payment-resolver/coinbase/orders/regular.json +0 -204
- package/test/_legacy/payment-resolver/coinbase/subscriptions/cancelled.json +0 -204
- package/test/_legacy/payment-resolver/coinbase/subscriptions/paid-2.json +0 -125
- package/test/_legacy/payment-resolver/index.js +0 -1558
- package/test/_legacy/payment-resolver/paypal/orders/refunded.json +0 -0
- package/test/_legacy/payment-resolver/paypal/orders/regular.json +0 -120
- package/test/_legacy/payment-resolver/paypal/subscriptions/active-refund-previous-stmnt.json +0 -323
- package/test/_legacy/payment-resolver/paypal/subscriptions/active.json +0 -192
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-in-trial.json +0 -125
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-not-complete.json +0 -76
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-overdue-2.json +0 -114
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-overdue.json +0 -114
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-active-to-cancelled.json +0 -111
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-active.json +0 -132
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-cancelled.json +0 -107
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-expired.json +0 -91
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-refund.json +0 -147
- package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-suspended.json +0 -120
- package/test/_legacy/payment-resolver/stripe/orders/refunded.json +0 -0
- package/test/_legacy/payment-resolver/stripe/orders/regular.json +0 -91
- package/test/_legacy/payment-resolver/stripe/subscriptions/active.json +0 -421
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-in-trial.json +0 -349
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-active-failed-authorization.json +0 -430
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-active.json +0 -319
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-cancelled.json +0 -319
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-refund.json +0 -414
- package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-suspended.json +0 -319
- package/test/_legacy/payment-resolver/stripe/subscriptions/unsure.json +0 -339
- package/test/_legacy/test-new +0 -1178
- package/test/_legacy/test.md +0 -89
- package/test/_legacy/usage.js +0 -175
- package/test/_legacy/user.js +0 -31
- package/test/ai/tools-live.js +0 -170
- package/test/boot/emulator-boots.js +0 -37
- package/test/content/blog-generate.js +0 -160
- package/test/email/campaign-send.js +0 -45
- package/test/email/consent-lifecycle.js +0 -257
- package/test/email/feedback-and-plain-send.js +0 -52
- package/test/email/fixtures/editorial.json +0 -30
- package/test/email/fixtures/field-report.json +0 -53
- package/test/email/marketing-lifecycle.js +0 -132
- package/test/email/newsletter-generate.js +0 -819
- package/test/email/newsletter-templates.js +0 -491
- package/test/email/templates.js +0 -207
- package/test/email/transactional-send.js +0 -34
- package/test/email/transactional.js +0 -560
- package/test/email/validation.js +0 -710
- package/test/events/auth-delete-race.js +0 -201
- package/test/events/payments/journey-payments-cancel-endpoint.js +0 -100
- package/test/events/payments/journey-payments-cancel.js +0 -182
- package/test/events/payments/journey-payments-discount.js +0 -89
- package/test/events/payments/journey-payments-failure.js +0 -146
- package/test/events/payments/journey-payments-legacy-product.js +0 -149
- package/test/events/payments/journey-payments-one-time-failure.js +0 -111
- package/test/events/payments/journey-payments-one-time.js +0 -136
- package/test/events/payments/journey-payments-plan-change.js +0 -144
- package/test/events/payments/journey-payments-refund-webhook.js +0 -180
- package/test/events/payments/journey-payments-suspend.js +0 -181
- package/test/events/payments/journey-payments-trial-cancel.js +0 -130
- package/test/events/payments/journey-payments-trial.js +0 -171
- package/test/events/payments/journey-payments-uid-resolution.js +0 -132
- package/test/events/payments/journey-payments-upgrade.js +0 -135
- package/test/fixtures/chargebee/invoice-one-time.json +0 -27
- package/test/fixtures/chargebee/subscription-active.json +0 -44
- package/test/fixtures/chargebee/subscription-cancelled.json +0 -42
- package/test/fixtures/chargebee/subscription-in-trial.json +0 -41
- package/test/fixtures/chargebee/subscription-legacy-plan.json +0 -41
- package/test/fixtures/chargebee/subscription-non-renewing.json +0 -41
- package/test/fixtures/chargebee/subscription-paused.json +0 -42
- package/test/fixtures/chargebee/webhook-payment-failed.json +0 -51
- package/test/fixtures/chargebee/webhook-subscription-created.json +0 -47
- package/test/fixtures/paypal/order-approved.json +0 -62
- package/test/fixtures/paypal/order-completed.json +0 -110
- package/test/fixtures/paypal/subscription-active.json +0 -76
- package/test/fixtures/paypal/subscription-cancelled.json +0 -50
- package/test/fixtures/paypal/subscription-suspended.json +0 -65
- package/test/fixtures/stripe/checkout-session-completed.json +0 -130
- package/test/fixtures/stripe/invoice-payment-failed.json +0 -148
- package/test/fixtures/stripe/invoice-subscription-payment-failed.json +0 -28
- package/test/fixtures/stripe/subscription-active.json +0 -161
- package/test/fixtures/stripe/subscription-canceled.json +0 -161
- package/test/fixtures/stripe/subscription-trialing.json +0 -161
- package/test/functions/admin/database-read.js +0 -134
- package/test/functions/admin/database-write.js +0 -159
- package/test/functions/admin/edit-post.js +0 -366
- package/test/functions/admin/firestore-query.js +0 -207
- package/test/functions/admin/firestore-read.js +0 -129
- package/test/functions/admin/firestore-write.js +0 -105
- package/test/functions/admin/get-stats.js +0 -115
- package/test/functions/admin/send-email.js +0 -119
- package/test/functions/admin/send-notification.js +0 -208
- package/test/functions/admin/write-repo-content.js +0 -223
- package/test/functions/general/add-marketing-contact.js +0 -335
- package/test/functions/general/fetch-post.js +0 -54
- package/test/functions/general/generate-uuid.js +0 -114
- package/test/functions/test/authenticate.js +0 -64
- package/test/functions/user/create-custom-token.js +0 -73
- package/test/functions/user/delete.js +0 -135
- package/test/functions/user/get-active-sessions.js +0 -111
- package/test/functions/user/get-subscription-info.js +0 -99
- package/test/functions/user/regenerate-api-keys.js +0 -156
- package/test/functions/user/resolve.js +0 -52
- package/test/functions/user/sign-out-all-sessions.js +0 -94
- package/test/functions/user/sign-up.js +0 -252
- package/test/functions/user/submit-feedback.js +0 -104
- package/test/functions/user/validate-settings.js +0 -82
- package/test/helpers/ai-request-payload.js +0 -300
- package/test/helpers/ai-test-provider.js +0 -202
- package/test/helpers/ai-tools-format.js +0 -383
- package/test/helpers/content/blog-auto-publisher.js +0 -484
- package/test/helpers/content/feed-parser.js +0 -528
- package/test/helpers/content/ghostii-blocks.js +0 -134
- package/test/helpers/content/ghostii-feed-integration.js +0 -404
- package/test/helpers/content/ghostii-write-article.js +0 -243
- package/test/helpers/environment.js +0 -230
- package/test/helpers/infer-contact.js +0 -113
- package/test/helpers/merge-line-files.js +0 -271
- package/test/helpers/payment/chargebee/parse-webhook.js +0 -413
- package/test/helpers/payment/chargebee/to-unified-one-time.js +0 -147
- package/test/helpers/payment/chargebee/to-unified-subscription.js +0 -648
- package/test/helpers/payment/paypal/parse-webhook.js +0 -539
- package/test/helpers/payment/paypal/to-unified-one-time.js +0 -382
- package/test/helpers/payment/paypal/to-unified-subscription.js +0 -820
- package/test/helpers/payment/stripe/parse-webhook.js +0 -447
- package/test/helpers/payment/stripe/to-unified-one-time.js +0 -306
- package/test/helpers/payment/stripe/to-unified-subscription.js +0 -708
- package/test/helpers/sanitize.js +0 -222
- package/test/helpers/slugify.js +0 -394
- package/test/helpers/storage.js +0 -194
- package/test/helpers/user.js +0 -755
- package/test/helpers/webhook-forward.js +0 -418
- package/test/mcp/discovery.js +0 -53
- package/test/mcp/oauth.js +0 -161
- package/test/mcp/protocol.js +0 -268
- package/test/mcp/roles.js +0 -188
- package/test/mcp/utils.js +0 -245
- package/test/routes/admin/create-post.js +0 -364
- package/test/routes/admin/database.js +0 -131
- package/test/routes/admin/deduplicate-image-alts.js +0 -190
- package/test/routes/admin/email.js +0 -114
- package/test/routes/admin/firestore-query.js +0 -204
- package/test/routes/admin/firestore.js +0 -127
- package/test/routes/admin/infer-contact.js +0 -218
- package/test/routes/admin/notification.js +0 -198
- package/test/routes/admin/post-resize-image.js +0 -184
- package/test/routes/admin/post.js +0 -368
- package/test/routes/admin/repo-content.js +0 -223
- package/test/routes/admin/stats.js +0 -112
- package/test/routes/content/post.js +0 -54
- package/test/routes/general/uuid.js +0 -115
- package/test/routes/marketing/campaign.js +0 -125
- package/test/routes/marketing/contact.js +0 -370
- package/test/routes/marketing/email-preferences.js +0 -292
- package/test/routes/marketing/push-send.js +0 -32
- package/test/routes/marketing/webhook-forward.js +0 -61
- package/test/routes/marketing/webhook.js +0 -639
- package/test/routes/payments/cancel.js +0 -140
- package/test/routes/payments/discount.js +0 -80
- package/test/routes/payments/dispute-alert.js +0 -320
- package/test/routes/payments/intent.js +0 -336
- package/test/routes/payments/portal.js +0 -92
- package/test/routes/payments/refund.js +0 -179
- package/test/routes/payments/trial-eligibility.js +0 -71
- package/test/routes/payments/webhook.js +0 -107
- package/test/routes/test/authenticate.js +0 -59
- package/test/routes/test/schema.js +0 -554
- package/test/routes/test/usage.js +0 -342
- package/test/routes/user/api-keys.js +0 -156
- package/test/routes/user/delete.js +0 -136
- package/test/routes/user/feedback.js +0 -104
- package/test/routes/user/sessions.js +0 -199
- package/test/routes/user/settings-validate.js +0 -82
- package/test/routes/user/signup.js +0 -542
- package/test/routes/user/subscription.js +0 -99
- package/test/routes/user/token.js +0 -73
- package/test/routes/user/user.js +0 -157
- package/test/rules/notifications.js +0 -410
- package/test/rules/payments-carts.js +0 -371
- package/test/rules/user.js +0 -396
package/plans/mcp2.md
DELETED
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
# MCP Role-Based Tool Scoping + Consumer Extensibility
|
|
2
|
-
|
|
3
|
-
## Context
|
|
4
|
-
|
|
5
|
-
The BEM MCP server currently works only for admins — a single `BACKEND_MANAGER_KEY` grants access to all 19 tools. Regular users can't connect at all, and consumer BEM projects have no way to add custom MCP tools. This plan adds:
|
|
6
|
-
|
|
7
|
-
1. **Role-based tool scoping** — tools tagged `admin`, `user`, or `public`; connections only see tools matching their role
|
|
8
|
-
2. **User authentication** — seamless OAuth sign-in flow + API key as long-lived credential
|
|
9
|
-
3. **Consumer MCP tools** — a single `functions/mcp.js` file in consumer projects
|
|
10
|
-
|
|
11
|
-
## Architecture
|
|
12
|
-
|
|
13
|
-
### Role Model
|
|
14
|
-
|
|
15
|
-
Every tool gets a `role` field:
|
|
16
|
-
|
|
17
|
-
| Role | Who sees it | Examples |
|
|
18
|
-
|------|-------------|---------|
|
|
19
|
-
| `admin` | Admin key connections only | firestore_read, send_email, run_cron |
|
|
20
|
-
| `user` | Authenticated users + admins | get_user, get_subscription, cancel_subscription |
|
|
21
|
-
| `public` | Everyone (including unauthenticated) | generate_uuid, health_check |
|
|
22
|
-
|
|
23
|
-
Admin sees ALL tools. User sees `user` + `public`. Unauthenticated sees only `public`. Defense-in-depth — even if someone calls an admin tool by name, the route still rejects with 403.
|
|
24
|
-
|
|
25
|
-
### Auth: How Users Connect (OAuth + Consumer's Website)
|
|
26
|
-
|
|
27
|
-
**The key insight:** users already have an API key (`api.privateKey`) on their Firestore account doc. It's long-lived, already works with `assistant.authenticate()`, and already encodes identity + access level. This is the credential.
|
|
28
|
-
|
|
29
|
-
**The UX:** Claude Code/Desktop opens a browser → user signs in on their familiar site → redirected back to Claude. Done. No copy-pasting tokens.
|
|
30
|
-
|
|
31
|
-
**The OAuth flow (step by step):**
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
1. Claude discovers endpoints:
|
|
35
|
-
GET /.well-known/oauth-authorization-server
|
|
36
|
-
→ { authorization_endpoint, token_endpoint, ... }
|
|
37
|
-
|
|
38
|
-
2. Claude opens browser to BEM authorize endpoint:
|
|
39
|
-
GET /backend-manager/mcp/authorize?redirect_uri=CLAUDE_CALLBACK&state=STATE
|
|
40
|
-
|
|
41
|
-
3. BEM authorize checks the request:
|
|
42
|
-
- If client_id === BACKEND_MANAGER_KEY → auto-redirect (admin, unchanged)
|
|
43
|
-
- Otherwise → redirect to consumer's /token page:
|
|
44
|
-
https://app.example.com/token?redirect_uri=CLAUDE_CALLBACK&state=STATE
|
|
45
|
-
|
|
46
|
-
4. User lands on their familiar website sign-in page.
|
|
47
|
-
Signs in with Google / email+password / whatever.
|
|
48
|
-
After sign-in, page gets Firebase ID token via webManager.auth().getIdToken()
|
|
49
|
-
|
|
50
|
-
5. Consumer's /token page redirects to CLAUDE_CALLBACK:
|
|
51
|
-
CLAUDE_CALLBACK?code=FIREBASE_ID_TOKEN&state=STATE
|
|
52
|
-
|
|
53
|
-
6. Claude exchanges code for access token:
|
|
54
|
-
POST /backend-manager/mcp/token
|
|
55
|
-
{ code: FIREBASE_ID_TOKEN }
|
|
56
|
-
|
|
57
|
-
7. BEM token endpoint:
|
|
58
|
-
- If code === BACKEND_MANAGER_KEY → return it as access_token (admin, unchanged)
|
|
59
|
-
- Otherwise → verify Firebase ID token with admin.auth().verifyIdToken()
|
|
60
|
-
→ look up user doc → return user's api.privateKey as access_token
|
|
61
|
-
|
|
62
|
-
8. Claude uses the API key for all future MCP requests:
|
|
63
|
-
Authorization: Bearer {api.privateKey}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
**Why API key, not JWT:**
|
|
67
|
-
- Firebase ID tokens expire in 1 hour — MCP connection would break constantly
|
|
68
|
-
- The API key never expires (until regenerated)
|
|
69
|
-
- `assistant.authenticate()` already handles API key → user lookup
|
|
70
|
-
- User can revoke by regenerating from account settings
|
|
71
|
-
|
|
72
|
-
**Why redirect to consumer's website instead of embedding Firebase Auth:**
|
|
73
|
-
- User sees their familiar sign-in page (branded, trusted)
|
|
74
|
-
- No need to embed Firebase Auth SDK in BEM's authorize HTML
|
|
75
|
-
- UJM already has a `/token` page — just needs a small update to support `redirect_uri` param
|
|
76
|
-
- Works with any auth provider the consumer has configured
|
|
77
|
-
|
|
78
|
-
### Auth Classification (Fast, No DB Call)
|
|
79
|
-
|
|
80
|
-
`resolveAuthInfo(token)` classifies the Bearer token for tool filtering:
|
|
81
|
-
|
|
82
|
-
- Token matches `BACKEND_MANAGER_KEY` → `role: 'admin'`
|
|
83
|
-
- Any other non-empty token → `role: 'user'` (API key from the OAuth flow)
|
|
84
|
-
- No token → `role: 'public'`
|
|
85
|
-
|
|
86
|
-
No DB call needed — actual validation happens at the route level when a tool is called.
|
|
87
|
-
|
|
88
|
-
### Consumer MCP Tools
|
|
89
|
-
|
|
90
|
-
Consumer tools live in a **single file**: `functions/mcp.js`. Keeps things simple since most consumer MCP tools are just route delegations pointing at routes already defined in `functions/routes/`.
|
|
91
|
-
|
|
92
|
-
```js
|
|
93
|
-
// functions/mcp.js
|
|
94
|
-
module.exports = [
|
|
95
|
-
// Route delegation — points at an existing route (works on stdio + HTTP)
|
|
96
|
-
{
|
|
97
|
-
name: 'get_sponsorship',
|
|
98
|
-
description: 'Get sponsorship details by ID',
|
|
99
|
-
role: 'user',
|
|
100
|
-
method: 'GET',
|
|
101
|
-
path: 'sponsorship',
|
|
102
|
-
inputSchema: {
|
|
103
|
-
type: 'object',
|
|
104
|
-
properties: {
|
|
105
|
-
id: { type: 'string', description: 'Sponsorship ID' },
|
|
106
|
-
},
|
|
107
|
-
required: ['id'],
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
// Handler mode — runs code directly (HTTP transport only, has full Manager context)
|
|
112
|
-
{
|
|
113
|
-
name: 'newsletter_stats',
|
|
114
|
-
description: 'Get newsletter stats for the past N days',
|
|
115
|
-
role: 'admin',
|
|
116
|
-
inputSchema: {
|
|
117
|
-
type: 'object',
|
|
118
|
-
properties: {
|
|
119
|
-
days: { type: 'number', description: 'Days to look back', default: 30 },
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
handler: async ({ Manager, assistant, user, params, libraries }) => {
|
|
123
|
-
const cutoff = Date.now() - (params.days || 30) * 86400000;
|
|
124
|
-
const snapshot = await libraries.admin.firestore()
|
|
125
|
-
.collection('newsletters')
|
|
126
|
-
.where('metadata.created.timestampUNIX', '>=', Math.floor(cutoff / 1000))
|
|
127
|
-
.get();
|
|
128
|
-
return { total: snapshot.docs.length };
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
];
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Consumer tools with the same name as a built-in tool override it (same precedence as consumer routes).
|
|
135
|
-
|
|
136
|
-
## File Changes
|
|
137
|
-
|
|
138
|
-
### 1. `src/mcp/tools.js` — Add `role` to every tool
|
|
139
|
-
|
|
140
|
-
| Tool | Role |
|
|
141
|
-
|------|------|
|
|
142
|
-
| `firestore_read/write/query` | `admin` |
|
|
143
|
-
| `send_email`, `send_notification` | `admin` |
|
|
144
|
-
| `sync_users`, `list_campaigns`, `create_campaign` | `admin` |
|
|
145
|
-
| `get_stats`, `run_cron`, `create_post`, `create_backup`, `run_hook` | `admin` |
|
|
146
|
-
| `get_user`, `get_subscription` | `user` |
|
|
147
|
-
| `cancel_subscription`, `refund_payment` | `user` |
|
|
148
|
-
| `generate_uuid`, `health_check` | `public` |
|
|
149
|
-
|
|
150
|
-
### 2. NEW: `src/mcp/utils.js` — Shared utilities
|
|
151
|
-
|
|
152
|
-
- **`resolveAuthInfo(token)`** — classifies token → `{ role, authType, token }`. Admin key check is instant; everything else = user.
|
|
153
|
-
- **`filterToolsByRole(tools, role)`** — admin→all, user→user+public, public→public only.
|
|
154
|
-
- **`loadConsumerTools(cwd)`** — checks for `${cwd}/mcp.js`, `require()`s it if it exists, validates shape, returns array.
|
|
155
|
-
- **`buildToolMap(builtinTools, consumerTools)`** — merges into a Map; consumer tools override same-name built-ins.
|
|
156
|
-
|
|
157
|
-
### 3. `src/mcp/client.js` — Support user auth tokens
|
|
158
|
-
|
|
159
|
-
Extend constructor to accept `{ baseUrl, backendManagerKey, userToken }`.
|
|
160
|
-
|
|
161
|
-
In `call()`:
|
|
162
|
-
- Has `backendManagerKey` → current behavior (key in query/body)
|
|
163
|
-
- Has `userToken` (no backendManagerKey) → put token in `Authorization: Bearer` header + `authenticationToken` query param for GET
|
|
164
|
-
- Neither → unauthenticated request
|
|
165
|
-
|
|
166
|
-
### 4. `src/mcp/index.js` — Stdio server with role filtering
|
|
167
|
-
|
|
168
|
-
- Import utils, call `resolveAuthInfo()` to determine role
|
|
169
|
-
- Call `loadConsumerTools(options.cwd)` if `cwd` is provided
|
|
170
|
-
- Merge + filter tools by role in `ListToolsRequestSchema` handler
|
|
171
|
-
- In `CallToolRequestSchema`: `path`-based tools via BEMClient. Handler-only tools return error explaining they require HTTP transport.
|
|
172
|
-
- Accept new `options.token` for user connections
|
|
173
|
-
|
|
174
|
-
### 5. `src/mcp/handler.js` — HTTP handler with OAuth user flow
|
|
175
|
-
|
|
176
|
-
**`handleAuthorize()`** — the big change:
|
|
177
|
-
- If `client_id` matches admin key → auto-redirect (current behavior, unchanged)
|
|
178
|
-
- Otherwise → **redirect to consumer's website** for sign-in:
|
|
179
|
-
- Build consumer auth URL from `Manager.config.brand.url` (or a configurable `mcp.authUrl` in backend-manager-config.json)
|
|
180
|
-
- Redirect to: `{consumerUrl}/token?redirect_uri={originalRedirectUri}&state={state}`
|
|
181
|
-
- The consumer's `/token` page handles sign-in, gets Firebase ID token, redirects back to Claude's callback
|
|
182
|
-
|
|
183
|
-
**`handleToken()`** — exchanges Firebase ID token for API key:
|
|
184
|
-
- If code matches admin key → return as `access_token` (unchanged)
|
|
185
|
-
- Otherwise → treat code as Firebase ID token:
|
|
186
|
-
1. `admin.auth().verifyIdToken(code)` to get UID
|
|
187
|
-
2. `admin.firestore().doc('users/{uid}').get()` to get user doc
|
|
188
|
-
3. Return `user.api.privateKey` as the `access_token`
|
|
189
|
-
4. If user has no API key, generate one and save it
|
|
190
|
-
|
|
191
|
-
**`handleMcpProtocol()`** — role-based tool filtering:
|
|
192
|
-
- Extract Bearer token, call `resolveAuthInfo()`
|
|
193
|
-
- Allow public connections (no 401 for empty tokens — just show public tools)
|
|
194
|
-
- Discover + merge consumer tools (cached at module scope)
|
|
195
|
-
- Filter tools by role in `ListToolsRequestSchema`
|
|
196
|
-
- In `CallToolRequestSchema`:
|
|
197
|
-
- `path`-based tools: BEMClient HTTP call (current behavior)
|
|
198
|
-
- `handler`-based tools: execute directly with `{ Manager, assistant, user, params, libraries }`
|
|
199
|
-
|
|
200
|
-
**Rename `isValidKey()` → `isAdminKey()`** for clarity.
|
|
201
|
-
|
|
202
|
-
### 6. `src/cli/commands/mcp.js` — New CLI flags
|
|
203
|
-
|
|
204
|
-
- `--token` (`-t`): user's API key (for user-level connections)
|
|
205
|
-
- Pass `cwd: functionsDir` to `startServer()` for consumer tool discovery
|
|
206
|
-
- When `--token` is provided, create BEMClient with userToken instead of backendManagerKey
|
|
207
|
-
|
|
208
|
-
### 7. Consumer's UJM `/token` page — Small update (separate repo)
|
|
209
|
-
|
|
210
|
-
The UJM `/token` page needs to support the MCP OAuth redirect flow:
|
|
211
|
-
- Detect `redirect_uri` and `state` query params
|
|
212
|
-
- After sign-in, get Firebase ID token via `webManager.auth().getIdToken()`
|
|
213
|
-
- Redirect to `redirect_uri?code={idToken}&state={state}`
|
|
214
|
-
|
|
215
|
-
This is a small addition to the existing `/token` page layout. Files:
|
|
216
|
-
- `ultimate-jekyll-manager/src/defaults/dist/_layouts/blueprint/auth/token.html`
|
|
217
|
-
- `ultimate-jekyll-manager/src/defaults/dist/_layouts/themes/classy/frontend/pages/auth/token.html`
|
|
218
|
-
|
|
219
|
-
### 8. `docs/mcp.md` — Documentation
|
|
220
|
-
|
|
221
|
-
- Add "Roles" section explaining admin/user/public scoping
|
|
222
|
-
- Add "User Authentication" section with the OAuth flow diagram
|
|
223
|
-
- Add "Consumer MCP Tools" section with `functions/mcp.js` format + examples
|
|
224
|
-
- Add CLI examples for user connections
|
|
225
|
-
- Add guide for configuring the consumer auth URL
|
|
226
|
-
|
|
227
|
-
## Implementation Order
|
|
228
|
-
|
|
229
|
-
1. `src/mcp/utils.js` (new) — foundation utilities
|
|
230
|
-
2. `src/mcp/tools.js` — add `role` to all 19 tools
|
|
231
|
-
3. `src/mcp/client.js` — user token support
|
|
232
|
-
4. `src/mcp/index.js` — stdio role filtering + consumer tools
|
|
233
|
-
5. `src/cli/commands/mcp.js` — new CLI flags
|
|
234
|
-
6. `src/mcp/handler.js` — HTTP role filtering + OAuth user flow + consumer tool handlers
|
|
235
|
-
7. UJM `/token` page update (separate repo)
|
|
236
|
-
8. `docs/mcp.md` — documentation
|
|
237
|
-
|
|
238
|
-
## Verification
|
|
239
|
-
|
|
240
|
-
1. **Existing admin flow**: `npx mgr mcp` with `BACKEND_MANAGER_KEY` → all 19 tools listed, all callable
|
|
241
|
-
2. **User flow (stdio)**: `npx mgr mcp --token <api-key>` → only user+public tools listed
|
|
242
|
-
3. **Public flow**: `npx mgr mcp` (no key, no token) → only public tools listed
|
|
243
|
-
4. **Consumer tools**: Create `functions/mcp.js` in a consumer project → tools appear in listing
|
|
244
|
-
5. **HTTP OAuth flow**: Connect from Claude Code/Desktop → redirected to consumer site → sign in → redirected back → user tools available
|
|
245
|
-
6. **Token exchange**: POST to `/mcp/token` with Firebase ID token → returns API key as access_token
|
|
246
|
-
7. **Role enforcement**: User calling an admin tool by name → unknown tool error (tool not in filtered list)
|
|
247
|
-
8. **Run `npx mgr test`** to verify no regressions
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Test Helper — direct provider lookups + removals via API
|
|
5
|
-
*
|
|
6
|
-
* Lets the live-test checklist verify SendGrid + Beehiiv state without
|
|
7
|
-
* clicking around in dashboards. Reuses the same provider helpers that
|
|
8
|
-
* BEM uses in production (findContact / removeContact).
|
|
9
|
-
*
|
|
10
|
-
* Usage (run from a consumer project's functions/ dir):
|
|
11
|
-
*
|
|
12
|
-
* node ../../../backend-manager/scripts/test-helper-providers.js find user@example.com
|
|
13
|
-
* node ../../../backend-manager/scripts/test-helper-providers.js purge user@example.com
|
|
14
|
-
*
|
|
15
|
-
* Or symlink: `ln -s ../../../backend-manager/scripts/test-helper-providers.js ./prov`
|
|
16
|
-
* then: `node ./prov find user@example.com`
|
|
17
|
-
*
|
|
18
|
-
* - find: prints whether the contact exists in SendGrid + Beehiiv (and the data shape).
|
|
19
|
-
* - purge: removes the contact from BOTH providers (idempotent; safe if absent).
|
|
20
|
-
*
|
|
21
|
-
* The script picks up:
|
|
22
|
-
* - SENDGRID_API_KEY, BEEHIIV_API_KEY from <cwd>/.env (functions/.env)
|
|
23
|
-
* - marketing.campaigns.listId, marketing.newsletter.publicationId from <cwd>/backend-manager-config.json
|
|
24
|
-
* - service-account from <cwd>/service-account.json
|
|
25
|
-
*
|
|
26
|
-
* Exit codes: 0 ok, 1 usage error, 2 provider error.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
const path = require('path');
|
|
30
|
-
const fs = require('fs');
|
|
31
|
-
|
|
32
|
-
const cwd = process.cwd();
|
|
33
|
-
const envPath = path.join(cwd, '.env');
|
|
34
|
-
const configPath = path.join(cwd, 'backend-manager-config.json');
|
|
35
|
-
const serviceAccountPath = path.join(cwd, 'service-account.json');
|
|
36
|
-
|
|
37
|
-
// --- sanity checks ---
|
|
38
|
-
if (!fs.existsSync(envPath)) {
|
|
39
|
-
console.error(`✗ Missing ${envPath} — run from the consumer's functions/ dir`);
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
if (!fs.existsSync(configPath)) {
|
|
43
|
-
console.error(`✗ Missing ${configPath} — run from the consumer's functions/ dir`);
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
if (!fs.existsSync(serviceAccountPath)) {
|
|
47
|
-
console.error(`✗ Missing ${serviceAccountPath} — run from the consumer's functions/ dir`);
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// --- parse args ---
|
|
52
|
-
const [, , cmd, email] = process.argv;
|
|
53
|
-
const VALID_CMDS = ['find', 'purge'];
|
|
54
|
-
|
|
55
|
-
if (!cmd || !VALID_CMDS.includes(cmd) || !email) {
|
|
56
|
-
console.error('Usage:');
|
|
57
|
-
console.error(' node test-helper-providers.js find <email>');
|
|
58
|
-
console.error(' node test-helper-providers.js purge <email>');
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// --- bootstrap env (dotenv style, minimal) ---
|
|
63
|
-
require('dotenv').config({ path: envPath });
|
|
64
|
-
|
|
65
|
-
if (!process.env.SENDGRID_API_KEY) {
|
|
66
|
-
console.error('✗ SENDGRID_API_KEY not set in .env');
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
if (!process.env.BEEHIIV_API_KEY) {
|
|
70
|
-
console.error('✗ BEEHIIV_API_KEY not set in .env');
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// --- bootstrap Manager so providers can read Manager.config.marketing.* ---
|
|
75
|
-
// The providers require '../../../index.js' which is the Manager singleton.
|
|
76
|
-
// We need to load BEM from the consumer's node_modules (not the BEM repo's own src)
|
|
77
|
-
// so it picks up the consumer's config + service account.
|
|
78
|
-
let Manager;
|
|
79
|
-
try {
|
|
80
|
-
const BackendManager = require(path.join(cwd, 'node_modules', 'backend-manager'));
|
|
81
|
-
Manager = (new BackendManager()).init({}, { setupFunctionsLegacy: false, log: false });
|
|
82
|
-
} catch (e) {
|
|
83
|
-
console.error('✗ Failed to bootstrap Manager from consumer node_modules:', e.message);
|
|
84
|
-
process.exit(2);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// --- load providers via the BEM Manager.libraries surface (preferred) or direct path ---
|
|
88
|
-
const sendgridProviderPath = path.join(cwd, 'node_modules', 'backend-manager', 'src', 'manager', 'libraries', 'email', 'providers', 'sendgrid.js');
|
|
89
|
-
const beehiivProviderPath = path.join(cwd, 'node_modules', 'backend-manager', 'src', 'manager', 'libraries', 'email', 'providers', 'beehiiv.js');
|
|
90
|
-
|
|
91
|
-
const sendgrid = require(sendgridProviderPath);
|
|
92
|
-
const beehiiv = require(beehiivProviderPath);
|
|
93
|
-
|
|
94
|
-
// --- commands ---
|
|
95
|
-
async function find(email) {
|
|
96
|
-
console.log(`Looking up ${email} on both providers...`);
|
|
97
|
-
|
|
98
|
-
const [sgContact, bhContact] = await Promise.all([
|
|
99
|
-
sendgrid.findContact(email).catch(e => ({ _error: e.message })),
|
|
100
|
-
beehiiv.findContact(email).catch(e => ({ _error: e.message })),
|
|
101
|
-
]);
|
|
102
|
-
|
|
103
|
-
console.log('\n── SendGrid ──');
|
|
104
|
-
if (sgContact?._error) {
|
|
105
|
-
console.log(` ✗ error: ${sgContact._error}`);
|
|
106
|
-
} else if (!sgContact) {
|
|
107
|
-
console.log(' ⊘ not found');
|
|
108
|
-
} else {
|
|
109
|
-
console.log(` ✓ found — id=${sgContact.id || '?'}, email=${sgContact.email || '?'}`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
console.log('\n── Beehiiv ──');
|
|
113
|
-
if (bhContact?._error) {
|
|
114
|
-
console.log(` ✗ error: ${bhContact._error}`);
|
|
115
|
-
} else if (!bhContact) {
|
|
116
|
-
console.log(' ⊘ not found');
|
|
117
|
-
} else {
|
|
118
|
-
console.log(` ✓ found — id=${bhContact.id || '?'}, email=${bhContact.email || '?'}, status=${bhContact.status || '?'}`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return { sgContact, bhContact };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async function purge(email) {
|
|
125
|
-
console.log(`Removing ${email} from both providers...`);
|
|
126
|
-
|
|
127
|
-
const [sgResult, bhResult] = await Promise.all([
|
|
128
|
-
sendgrid.removeContact(email).catch(e => ({ _error: e.message })),
|
|
129
|
-
beehiiv.removeContact(email).catch(e => ({ _error: e.message })),
|
|
130
|
-
]);
|
|
131
|
-
|
|
132
|
-
console.log('\n── SendGrid ──');
|
|
133
|
-
if (sgResult?._error) {
|
|
134
|
-
console.log(` ✗ error: ${sgResult._error}`);
|
|
135
|
-
} else {
|
|
136
|
-
console.log(` ✓ ${JSON.stringify(sgResult)}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
console.log('\n── Beehiiv ──');
|
|
140
|
-
if (bhResult?._error) {
|
|
141
|
-
console.log(` ✗ error: ${bhResult._error}`);
|
|
142
|
-
} else {
|
|
143
|
-
console.log(` ✓ ${JSON.stringify(bhResult)}`);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return { sgResult, bhResult };
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// --- main ---
|
|
150
|
-
(async () => {
|
|
151
|
-
try {
|
|
152
|
-
if (cmd === 'find') {
|
|
153
|
-
await find(email);
|
|
154
|
-
} else if (cmd === 'purge') {
|
|
155
|
-
await purge(email);
|
|
156
|
-
}
|
|
157
|
-
process.exit(0);
|
|
158
|
-
} catch (e) {
|
|
159
|
-
console.error('✗ Unexpected error:', e);
|
|
160
|
-
process.exit(2);
|
|
161
|
-
}
|
|
162
|
-
})();
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Fetches the latest disposable email domain list from GitHub and saves it as JSON.
|
|
5
|
-
*
|
|
6
|
-
* Source: https://github.com/disposable-email-domains/disposable-email-domains
|
|
7
|
-
* (curated, ~5k domains, low false-positive rate)
|
|
8
|
-
*
|
|
9
|
-
* Run manually: node scripts/update-disposable-domains.js
|
|
10
|
-
* Runs automatically on: npm prepublishOnly
|
|
11
|
-
*/
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
const SOURCE_URL = 'https://raw.githubusercontent.com/disposable-email-domains/disposable-email-domains/main/disposable_email_blocklist.conf';
|
|
16
|
-
const OUTPUT_PATH = path.join(__dirname, '..', 'src', 'manager', 'libraries', 'email', 'data', 'disposable-domains.json');
|
|
17
|
-
|
|
18
|
-
async function main() {
|
|
19
|
-
console.log('Fetching disposable domain list...');
|
|
20
|
-
|
|
21
|
-
const response = await fetch(SOURCE_URL);
|
|
22
|
-
|
|
23
|
-
if (!response.ok) {
|
|
24
|
-
throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const text = await response.text();
|
|
28
|
-
const domains = text
|
|
29
|
-
.trim()
|
|
30
|
-
.split('\n')
|
|
31
|
-
.map(d => d.trim().toLowerCase())
|
|
32
|
-
.filter(Boolean);
|
|
33
|
-
|
|
34
|
-
const unique = [...new Set(domains)].sort();
|
|
35
|
-
|
|
36
|
-
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(unique, null, 2) + '\n');
|
|
37
|
-
|
|
38
|
-
console.log(`Updated disposable-domains.json: ${unique.length} domains`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
main().catch((e) => {
|
|
42
|
-
console.warn('Warning: Failed to update disposable domains:', e.message);
|
|
43
|
-
console.warn('Using existing list. Run manually later: node scripts/update-disposable-domains.js');
|
|
44
|
-
});
|
package/templates/_.env
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# ========== Default Values ==========
|
|
2
|
-
# GitHub
|
|
3
|
-
GH_TOKEN=""
|
|
4
|
-
|
|
5
|
-
# Backend Manager
|
|
6
|
-
BACKEND_MANAGER_KEY=""
|
|
7
|
-
BACKEND_MANAGER_WEBHOOK_KEY=""
|
|
8
|
-
BACKEND_MANAGER_NAMESPACE=""
|
|
9
|
-
BACKEND_MANAGER_OPENAI_API_KEY=""
|
|
10
|
-
BACKEND_MANAGER_ANTHROPIC_API_KEY=""
|
|
11
|
-
|
|
12
|
-
# AI
|
|
13
|
-
OPENAI_API_KEY=""
|
|
14
|
-
ANTHROPIC_API_KEY=""
|
|
15
|
-
CLAUDE_CODE_OAUTH_TOKEN=""
|
|
16
|
-
|
|
17
|
-
# Payment Processors
|
|
18
|
-
PAYPAL_CLIENT_SECRET=""
|
|
19
|
-
STRIPE_SECRET_KEY=""
|
|
20
|
-
CHARGEBEE_API_KEY=""
|
|
21
|
-
COINBASE_API_KEY=""
|
|
22
|
-
|
|
23
|
-
# Analytics
|
|
24
|
-
GOOGLE_ANALYTICS_SECRET=""
|
|
25
|
-
META_ACCESS_TOKEN=""
|
|
26
|
-
TIKTOK_ACCESS_TOKEN=""
|
|
27
|
-
|
|
28
|
-
# Security
|
|
29
|
-
CLOUDFLARE_TOKEN=""
|
|
30
|
-
RECAPTCHA_SECRET_KEY=""
|
|
31
|
-
|
|
32
|
-
# Email & Newsletter
|
|
33
|
-
SENDGRID_API_KEY=""
|
|
34
|
-
BEEHIIV_API_KEY=""
|
|
35
|
-
NEVERBOUNCE_API_KEY=""
|
|
36
|
-
ZEROBOUNCE_API_KEY=""
|
|
37
|
-
UNSUBSCRIBE_HMAC_KEY=""
|
|
38
|
-
APOLLO_API_KEY=""
|
|
39
|
-
|
|
40
|
-
# ========== Custom Values ==========
|
|
41
|
-
# Add your custom environment variables below this line
|
|
42
|
-
# ...
|
package/templates/_.gitignore
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# ========== Default Values ==========
|
|
2
|
-
# macOS
|
|
3
|
-
.DS_Store
|
|
4
|
-
|
|
5
|
-
# Logs
|
|
6
|
-
logs
|
|
7
|
-
*.log
|
|
8
|
-
npm-debug.log*
|
|
9
|
-
yarn-debug.log*
|
|
10
|
-
yarn-error.log*
|
|
11
|
-
firebase-debug.log*
|
|
12
|
-
|
|
13
|
-
# Firebase cache
|
|
14
|
-
.firebase/
|
|
15
|
-
|
|
16
|
-
# Firebase config
|
|
17
|
-
.firebaserc
|
|
18
|
-
|
|
19
|
-
# Runtime data
|
|
20
|
-
pids
|
|
21
|
-
*.pid
|
|
22
|
-
*.seed
|
|
23
|
-
*.pid.lock
|
|
24
|
-
|
|
25
|
-
# Coverage directory
|
|
26
|
-
coverage
|
|
27
|
-
.nyc_output
|
|
28
|
-
|
|
29
|
-
# Dependency directories
|
|
30
|
-
node_modules/
|
|
31
|
-
|
|
32
|
-
# Optional npm cache directory
|
|
33
|
-
.npm
|
|
34
|
-
|
|
35
|
-
# Optional eslint cache
|
|
36
|
-
.eslintcache
|
|
37
|
-
|
|
38
|
-
# Output of 'npm pack'
|
|
39
|
-
*.tgz
|
|
40
|
-
|
|
41
|
-
# Yarn Integrity file
|
|
42
|
-
.yarn-integrity
|
|
43
|
-
|
|
44
|
-
# dotenv environment variables file
|
|
45
|
-
.env*
|
|
46
|
-
|
|
47
|
-
# BEM specific
|
|
48
|
-
.runtimeconfig.json
|
|
49
|
-
service-account*.json
|
|
50
|
-
bem-reload-trigger.js
|
|
51
|
-
.temp/
|
|
52
|
-
_legacy
|
|
53
|
-
|
|
54
|
-
# Root proxy (generated by setup)
|
|
55
|
-
/package.json
|
|
56
|
-
/package-lock.json
|
|
57
|
-
|
|
58
|
-
# ========== Custom Values ==========
|
|
59
|
-
# Add your custom ignore patterns below this line
|
|
60
|
-
# ...
|