@omega.js/backend 0.1.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 +98 -0
- package/README.md +1053 -0
- package/bin/omega +2 -0
- package/bin/omega-backend +2 -0
- package/bin/omg +2 -0
- package/cli.js +3 -0
- package/dist/cli/command-table.js +268 -0
- package/dist/cli/commands/auth.js +259 -0
- package/dist/cli/commands/base-command.js +451 -0
- package/dist/cli/commands/build.js +27 -0
- package/dist/cli/commands/clean.js +13 -0
- package/dist/cli/commands/clear.js +11 -0
- package/dist/cli/commands/cwd.js +9 -0
- package/dist/cli/commands/deploy.js +205 -0
- package/dist/cli/commands/emulator-orphans.js +440 -0
- package/dist/cli/commands/emulator.js +1829 -0
- package/dist/cli/commands/firebase-init.js +101 -0
- package/dist/cli/commands/firestore.js +261 -0
- package/dist/cli/commands/indexes.js +51 -0
- package/dist/cli/commands/install.js +151 -0
- package/dist/cli/commands/logs.js +358 -0
- package/dist/cli/commands/mcp.js +41 -0
- package/dist/cli/commands/migrate-markers.js +176 -0
- package/dist/cli/commands/migrate-rules.js +90 -0
- package/dist/cli/commands/migrate.js +59 -0
- package/dist/cli/commands/serve.js +208 -0
- package/dist/cli/commands/setup-tests/base-test.js +174 -0
- package/dist/cli/commands/setup-tests/emulator-config.js +109 -0
- package/dist/cli/commands/setup-tests/env-runtime-config-deprecated.js +47 -0
- package/dist/cli/commands/setup-tests/firebase-admin.js +49 -0
- package/dist/cli/commands/setup-tests/firebase-auth.js +26 -0
- package/dist/cli/commands/setup-tests/firebase-cli.js +26 -0
- package/dist/cli/commands/setup-tests/firebase-functions.js +49 -0
- package/dist/cli/commands/setup-tests/firestore-indexes-file.js +72 -0
- package/dist/cli/commands/setup-tests/firestore-indexes-in-json.js +20 -0
- package/dist/cli/commands/setup-tests/firestore-indexes-required.js +108 -0
- package/dist/cli/commands/setup-tests/firestore-indexes-synced.js +236 -0
- package/dist/cli/commands/setup-tests/firestore-rules-file.js +115 -0
- package/dist/cli/commands/setup-tests/firestore-rules-in-json.js +49 -0
- package/dist/cli/commands/setup-tests/functions-package.js +44 -0
- package/dist/cli/commands/setup-tests/gcloud-cli.js +26 -0
- package/dist/cli/commands/setup-tests/gitignore.js +122 -0
- package/dist/cli/commands/setup-tests/helpers/merge-line-files.js +28 -0
- package/dist/cli/commands/setup-tests/helpers/required-indexes.js +109 -0
- package/dist/cli/commands/setup-tests/helpers/seed-campaigns.js +246 -0
- package/dist/cli/commands/setup-tests/helpers.js +72 -0
- package/dist/cli/commands/setup-tests/hosting-folder.js +23 -0
- package/dist/cli/commands/setup-tests/hosting-rewrites.js +52 -0
- package/dist/cli/commands/setup-tests/index.js +111 -0
- package/dist/cli/commands/setup-tests/is-firebase-project.js +21 -0
- package/dist/cli/commands/setup-tests/java-installed.js +27 -0
- package/dist/cli/commands/setup-tests/legacy-tests-cleanup.js +43 -0
- package/dist/cli/commands/setup-tests/marketing-campaigns-seeded.js +230 -0
- package/dist/cli/commands/setup-tests/node-version.js +60 -0
- package/dist/cli/commands/setup-tests/npm-project-scripts.js +42 -0
- package/dist/cli/commands/setup-tests/nvmrc-version.js +36 -0
- package/dist/cli/commands/setup-tests/omega-backend.js +42 -0
- package/dist/cli/commands/setup-tests/omega-config.js +84 -0
- package/dist/cli/commands/setup-tests/project-directories.js +34 -0
- package/dist/cli/commands/setup-tests/project-id-consistency.js +201 -0
- package/dist/cli/commands/setup-tests/public-html-files.js +22 -0
- package/dist/cli/commands/setup-tests/realtime-rules-file.js +69 -0
- package/dist/cli/commands/setup-tests/realtime-rules-in-json.js +20 -0
- package/dist/cli/commands/setup-tests/remoteconfig-template-file.js +32 -0
- package/dist/cli/commands/setup-tests/remoteconfig-template-in-json.js +31 -0
- package/dist/cli/commands/setup-tests/service-account.js +86 -0
- package/dist/cli/commands/setup-tests/storage-lifecycle-policy.js +81 -0
- package/dist/cli/commands/setup-tests/storage-rules-file.js +32 -0
- package/dist/cli/commands/setup-tests/storage-rules-in-json.js +20 -0
- package/dist/cli/commands/stripe.js +14 -0
- package/dist/cli/commands/test-lanes/stripe-live.js +440 -0
- package/dist/cli/commands/test.js +976 -0
- package/dist/cli/commands/update.js +27 -0
- package/dist/cli/commands/version.js +10 -0
- package/dist/cli/commands/watch.js +196 -0
- package/dist/cli/flags.js +13 -0
- package/dist/cli/index.js +173 -0
- package/dist/cli/run.js +33 -0
- package/dist/cli/utils/attach-log-file.js +4 -0
- package/dist/cli/utils/compile-rules.js +1155 -0
- package/dist/cli/utils/ensure-target.js +314 -0
- package/dist/cli/utils/project-type.js +140 -0
- package/dist/cli/utils/public-files.js +49 -0
- package/dist/cli/utils/safe-install.js +4 -0
- package/dist/cli/utils/spawn-shell.js +94 -0
- package/dist/cli/utils/stage-functions.js +338 -0
- package/dist/cli/utils/stage-local-packages.js +210 -0
- package/dist/cli/utils/target-checks.js +161 -0
- package/dist/cli/utils/target.js +24 -0
- package/dist/cli/utils/ui.js +292 -0
- package/dist/defaults/AGENTS.md +125 -0
- package/dist/defaults/CHANGELOG.md +15 -0
- package/dist/defaults/CLAUDE.md +1 -0
- package/dist/defaults/_.gitignore +65 -0
- package/dist/defaults/docs/README.md +17 -0
- package/dist/defaults/test/README.md +65 -0
- package/dist/defaults/test/_init.js +14 -0
- package/dist/defaults/test/helpers/connect-trap.js +72 -0
- package/dist/defaults/test/unit/registration.test.js +143 -0
- package/dist/defaults/test/unit/rules-posture.test.js +101 -0
- package/dist/defaults/test/unit/socket-free.test.js +43 -0
- package/dist/manager/events/auth/before-create.js +89 -0
- package/dist/manager/events/auth/before-signin.js +76 -0
- package/dist/manager/events/auth/on-create.js +112 -0
- package/dist/manager/events/auth/on-delete.js +141 -0
- package/dist/manager/events/auth/utils.js +93 -0
- package/dist/manager/events/cron/daily/blog-auto-publisher.js +287 -0
- package/dist/manager/events/cron/daily/data-requests.js +57 -0
- package/dist/manager/events/cron/daily/expire-paypal-cancellations.js +191 -0
- package/dist/manager/events/cron/daily/marketing-prune.js +486 -0
- package/dist/manager/events/cron/daily/reset-usage.js +188 -0
- package/dist/manager/events/cron/daily/trial-lapse-sweep.js +355 -0
- package/dist/manager/events/cron/daily.js +3 -0
- package/dist/manager/events/cron/frequent/abandoned-carts.js +204 -0
- package/dist/manager/events/cron/frequent/email-queue.js +71 -0
- package/dist/manager/events/cron/frequent/marketing-campaigns.js +463 -0
- package/dist/manager/events/cron/frequent/retry-failed-webhooks.js +70 -0
- package/dist/manager/events/cron/frequent.js +3 -0
- package/dist/manager/events/cron/runner.js +64 -0
- package/dist/manager/events/firestore/notifications/on-write.js +123 -0
- package/dist/manager/events/firestore/payments-disputes/on-write.js +256 -0
- package/dist/manager/events/firestore/payments-disputes/providers/stripe.js +218 -0
- package/dist/manager/events/firestore/payments-disputes/providers/test.js +231 -0
- package/dist/manager/events/firestore/payments-webhooks/analytics.js +687 -0
- package/dist/manager/events/firestore/payments-webhooks/on-write.js +1224 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/index.js +395 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-completed.js +58 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-failed.js +28 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-refunded.js +30 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/send-email.js +74 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/cancellation-removed.js +14 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/cancellation-requested.js +28 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/checkout-declined.js +18 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/new-subscription.js +67 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-failed.js +25 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-recovered.js +26 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-refunded.js +34 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/plan-changed.js +42 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/subscription-cancelled.js +33 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/subscription-winback.js +17 -0
- package/dist/manager/functions/_legacy/actions/create-post-handler.js +188 -0
- package/dist/manager/functions/_legacy/actions/generate-uuid.js +63 -0
- package/dist/manager/functions/_legacy/actions/sign-up-handler.js +205 -0
- package/dist/manager/functions/_legacy/admin/create-post.js +207 -0
- package/dist/manager/functions/_legacy/admin/firestore-write.js +72 -0
- package/dist/manager/functions/_legacy/admin/get-stats.js +218 -0
- package/dist/manager/functions/_legacy/admin/query.js +198 -0
- package/dist/manager/functions/_legacy/admin/send-notification.js +206 -0
- package/dist/manager/functions/_legacy/template.js +33 -0
- package/dist/manager/functions/_legacy/test/authenticate.js +40 -0
- package/dist/manager/functions/_legacy/test/webhook.js +37 -0
- package/dist/manager/functions/wrappers/mailchimp/addToList.js +25 -0
- package/dist/manager/helpers/analytics.js +498 -0
- package/dist/manager/helpers/api-manager.js +313 -0
- package/dist/manager/helpers/backend-router.js +37 -0
- package/dist/manager/helpers/context/authenticate.js +215 -0
- package/dist/manager/helpers/context/client-info.js +91 -0
- package/dist/manager/helpers/context/index.js +228 -0
- package/dist/manager/helpers/context/logging.js +150 -0
- package/dist/manager/helpers/context/parse.js +160 -0
- package/dist/manager/helpers/context/respond.js +247 -0
- package/dist/manager/helpers/event-middleware.js +109 -0
- package/dist/manager/helpers/metadata.js +32 -0
- package/dist/manager/helpers/middleware.js +541 -0
- package/dist/manager/helpers/redact-secret.js +25 -0
- package/dist/manager/helpers/resolved-config.js +34 -0
- package/dist/manager/helpers/roles.js +69 -0
- package/dist/manager/helpers/safe-compare.js +31 -0
- package/dist/manager/helpers/schema-engine.js +314 -0
- package/dist/manager/helpers/schema-zod.js +203 -0
- package/dist/manager/helpers/settings.js +215 -0
- package/dist/manager/helpers/usage.js +541 -0
- package/dist/manager/helpers/user.js +57 -0
- package/dist/manager/helpers/utilities.js +565 -0
- package/dist/manager/index.js +1404 -0
- package/dist/manager/libraries/abandoned-cart-config.js +12 -0
- package/dist/manager/libraries/ai/index.js +321 -0
- package/dist/manager/libraries/ai/prompt.js +85 -0
- package/dist/manager/libraries/ai/providers/anthropic-format.js +297 -0
- package/dist/manager/libraries/ai/providers/anthropic.js +169 -0
- package/dist/manager/libraries/ai/providers/claude-code.js +183 -0
- package/dist/manager/libraries/ai/providers/openai.js +1272 -0
- package/dist/manager/libraries/ai/providers/test.js +257 -0
- package/dist/manager/libraries/ai/tokens.js +54 -0
- package/dist/manager/libraries/analytics/conversions.js +478 -0
- package/dist/manager/libraries/analytics/match-data.js +573 -0
- package/dist/manager/libraries/analytics/signup.js +120 -0
- package/dist/manager/libraries/auth-user.js +46 -0
- package/dist/manager/libraries/content/feed-parser.js +198 -0
- package/dist/manager/libraries/content/ghostii.js +191 -0
- package/dist/manager/libraries/content/source-resolver.js +629 -0
- package/dist/manager/libraries/email/constants.js +532 -0
- package/dist/manager/libraries/email/data/blocked-local-parts.json +55 -0
- package/dist/manager/libraries/email/data/blocked-local-patterns.js +14 -0
- package/dist/manager/libraries/email/data/corporate-domains.json +23 -0
- package/dist/manager/libraries/email/data/custom-disposable-domains.json +58 -0
- package/dist/manager/libraries/email/data/disposable-domains.json +8184 -0
- package/dist/manager/libraries/email/data/typo-domains.js +83 -0
- package/dist/manager/libraries/email/disposable-domains.js +92 -0
- package/dist/manager/libraries/email/generators/lib/filter.js +179 -0
- package/dist/manager/libraries/email/generators/lib/image-host.js +344 -0
- package/dist/manager/libraries/email/generators/lib/image-illustrator.js +154 -0
- package/dist/manager/libraries/email/generators/lib/markdown-renderer.js +294 -0
- package/dist/manager/libraries/email/generators/lib/mjml-template.js +120 -0
- package/dist/manager/libraries/email/generators/lib/structure.js +299 -0
- package/dist/manager/libraries/email/generators/lib/svg-illustrator.js +197 -0
- package/dist/manager/libraries/email/generators/lib/templates/base.js +229 -0
- package/dist/manager/libraries/email/generators/lib/templates/card.js +33 -0
- package/dist/manager/libraries/email/generators/lib/templates/classic-schema.js +59 -0
- package/dist/manager/libraries/email/generators/lib/templates/clean.js +82 -0
- package/dist/manager/libraries/email/generators/lib/templates/editorial/helpers.js +100 -0
- package/dist/manager/libraries/email/generators/lib/templates/editorial/index.js +318 -0
- package/dist/manager/libraries/email/generators/lib/templates/feedback.js +101 -0
- package/dist/manager/libraries/email/generators/lib/templates/field-report/helpers.js +138 -0
- package/dist/manager/libraries/email/generators/lib/templates/field-report/index.js +494 -0
- package/dist/manager/libraries/email/generators/lib/templates/index.js +47 -0
- package/dist/manager/libraries/email/generators/lib/templates/newsletter-shared.js +610 -0
- package/dist/manager/libraries/email/generators/lib/templates/order.js +461 -0
- package/dist/manager/libraries/email/generators/lib/templates/plain.js +83 -0
- package/dist/manager/libraries/email/generators/lib/templates/shared-campaign.js +64 -0
- package/dist/manager/libraries/email/generators/newsletter.js +899 -0
- package/dist/manager/libraries/email/index.js +146 -0
- package/dist/manager/libraries/email/marketing/index.js +754 -0
- package/dist/manager/libraries/email/prepare.js +365 -0
- package/dist/manager/libraries/email/providers/beehiiv.js +589 -0
- package/dist/manager/libraries/email/providers/sendgrid.js +845 -0
- package/dist/manager/libraries/email/transactional/index.js +510 -0
- package/dist/manager/libraries/email/utm.js +86 -0
- package/dist/manager/libraries/email/validation-provider-neverbounce.js +70 -0
- package/dist/manager/libraries/email/validation-provider-zerobounce.js +42 -0
- package/dist/manager/libraries/email/validation.js +255 -0
- package/dist/manager/libraries/env.js +198 -0
- package/dist/manager/libraries/infer-contact.js +101 -0
- package/dist/manager/libraries/load-provider.js +65 -0
- package/dist/manager/libraries/notification.js +256 -0
- package/dist/manager/libraries/openai.js +13 -0
- package/dist/manager/libraries/payment/discount-codes.js +204 -0
- package/dist/manager/libraries/payment/fetch-failure.js +56 -0
- package/dist/manager/libraries/payment/license.js +44 -0
- package/dist/manager/libraries/payment/order-id.js +57 -0
- package/dist/manager/libraries/payment/provider-errors.js +71 -0
- package/dist/manager/libraries/payment/providers/chargebee.js +817 -0
- package/dist/manager/libraries/payment/providers/coinbase.js +330 -0
- package/dist/manager/libraries/payment/providers/paypal.js +987 -0
- package/dist/manager/libraries/payment/providers/stripe.js +755 -0
- package/dist/manager/libraries/payment/providers/test.js +250 -0
- package/dist/manager/libraries/payment/refund-linkage.js +78 -0
- package/dist/manager/libraries/payment/refund-policy.js +113 -0
- package/dist/manager/libraries/payment/winback.js +55 -0
- package/dist/manager/libraries/prompts/infer-contact.md +78 -0
- package/dist/manager/libraries/rate-limits.js +17 -0
- package/dist/manager/libraries/recaptcha.js +58 -0
- package/dist/manager/libraries/user-doc.js +234 -0
- package/dist/manager/routes/admin/backup/post.js +106 -0
- package/dist/manager/routes/admin/cron/post.js +37 -0
- package/dist/manager/routes/admin/database/get.js +35 -0
- package/dist/manager/routes/admin/database/post.js +34 -0
- package/dist/manager/routes/admin/email/post.js +74 -0
- package/dist/manager/routes/admin/firestore/get.js +35 -0
- package/dist/manager/routes/admin/firestore/post.js +56 -0
- package/dist/manager/routes/admin/firestore/query/post.js +128 -0
- package/dist/manager/routes/admin/hook/post.js +104 -0
- package/dist/manager/routes/admin/infer-contact/post.js +35 -0
- package/dist/manager/routes/admin/notification/post.js +37 -0
- package/dist/manager/routes/admin/payment/post.js +56 -0
- package/dist/manager/routes/admin/post/deduplicate-image-alts.js +52 -0
- package/dist/manager/routes/admin/post/dispatch-deploy.js +36 -0
- package/dist/manager/routes/admin/post/post.js +487 -0
- package/dist/manager/routes/admin/post/put.js +146 -0
- package/dist/manager/routes/admin/post/templates/post.html +14 -0
- package/dist/manager/routes/admin/repo/content/post.js +106 -0
- package/dist/manager/routes/admin/stats/get.js +222 -0
- package/dist/manager/routes/admin/users/disable/post.js +50 -0
- package/dist/manager/routes/admin/users/list/get.js +110 -0
- package/dist/manager/routes/admin/users/sync/post.js +119 -0
- package/dist/manager/routes/brand/get.js +26 -0
- package/dist/manager/routes/content/post/get.js +110 -0
- package/dist/manager/routes/general/email/post.js +89 -0
- package/dist/manager/routes/general/email/templates/general/download-app-link.js +42 -0
- package/dist/manager/routes/general/uuid/post.js +31 -0
- package/dist/manager/routes/handler/post/post.js +142 -0
- package/dist/manager/routes/health/get.js +43 -0
- package/dist/manager/routes/index.js +11 -0
- package/dist/manager/routes/marketing/campaign/delete.js +45 -0
- package/dist/manager/routes/marketing/campaign/get.js +69 -0
- package/dist/manager/routes/marketing/campaign/post.js +124 -0
- package/dist/manager/routes/marketing/campaign/put.js +86 -0
- package/dist/manager/routes/marketing/campaign/utils.js +59 -0
- package/dist/manager/routes/marketing/contact/delete.js +100 -0
- package/dist/manager/routes/marketing/contact/post.js +149 -0
- package/dist/manager/routes/marketing/contact/put.js +37 -0
- package/dist/manager/routes/marketing/email-preferences/post.js +275 -0
- package/dist/manager/routes/marketing/webhook/forward/post.js +170 -0
- package/dist/manager/routes/marketing/webhook/post.js +123 -0
- package/dist/manager/routes/marketing/webhook/providers/beehiiv.js +197 -0
- package/dist/manager/routes/marketing/webhook/providers/sendgrid.js +194 -0
- package/dist/manager/routes/payments/cancel/_is-trialing.js +40 -0
- package/dist/manager/routes/payments/cancel/post.js +149 -0
- package/dist/manager/routes/payments/cancel/providers/chargebee.js +41 -0
- package/dist/manager/routes/payments/cancel/providers/paypal.js +56 -0
- package/dist/manager/routes/payments/cancel/providers/stripe.js +33 -0
- package/dist/manager/routes/payments/cancel/providers/test.js +118 -0
- package/dist/manager/routes/payments/discount/get.js +25 -0
- package/dist/manager/routes/payments/dispute-alert/post.js +117 -0
- package/dist/manager/routes/payments/dispute-alert/providers/chargeblast.js +55 -0
- package/dist/manager/routes/payments/intent/post.js +341 -0
- package/dist/manager/routes/payments/intent/providers/chargebee.js +197 -0
- package/dist/manager/routes/payments/intent/providers/coinbase.js +94 -0
- package/dist/manager/routes/payments/intent/providers/paypal.js +244 -0
- package/dist/manager/routes/payments/intent/providers/stripe.js +141 -0
- package/dist/manager/routes/payments/intent/providers/test.js +341 -0
- package/dist/manager/routes/payments/plan/post.js +147 -0
- package/dist/manager/routes/payments/plan/providers/chargebee.js +62 -0
- package/dist/manager/routes/payments/plan/providers/paypal.js +62 -0
- package/dist/manager/routes/payments/plan/providers/stripe.js +59 -0
- package/dist/manager/routes/payments/plan/providers/test.js +113 -0
- package/dist/manager/routes/payments/portal/post.js +113 -0
- package/dist/manager/routes/payments/portal/providers/chargebee.js +62 -0
- package/dist/manager/routes/payments/portal/providers/paypal.js +25 -0
- package/dist/manager/routes/payments/portal/providers/stripe.js +62 -0
- package/dist/manager/routes/payments/portal/providers/test.js +18 -0
- package/dist/manager/routes/payments/refund/post.js +207 -0
- package/dist/manager/routes/payments/refund/providers/chargebee.js +147 -0
- package/dist/manager/routes/payments/refund/providers/coinbase.js +40 -0
- package/dist/manager/routes/payments/refund/providers/paypal.js +239 -0
- package/dist/manager/routes/payments/refund/providers/stripe.js +160 -0
- package/dist/manager/routes/payments/refund/providers/test.js +204 -0
- package/dist/manager/routes/payments/trial-eligibility/get.js +29 -0
- package/dist/manager/routes/payments/uncancel/post.js +106 -0
- package/dist/manager/routes/payments/uncancel/providers/chargebee.js +30 -0
- package/dist/manager/routes/payments/uncancel/providers/paypal.js +25 -0
- package/dist/manager/routes/payments/uncancel/providers/stripe.js +27 -0
- package/dist/manager/routes/payments/uncancel/providers/test.js +114 -0
- package/dist/manager/routes/payments/webhook/post.js +157 -0
- package/dist/manager/routes/payments/webhook/providers/chargebee.js +218 -0
- package/dist/manager/routes/payments/webhook/providers/coinbase.js +91 -0
- package/dist/manager/routes/payments/webhook/providers/paypal.js +214 -0
- package/dist/manager/routes/payments/webhook/providers/stripe.js +182 -0
- package/dist/manager/routes/payments/webhook/providers/test.js +18 -0
- package/dist/manager/routes/payments/winback/post.js +276 -0
- package/dist/manager/routes/payments/winback/providers/chargebee.js +24 -0
- package/dist/manager/routes/payments/winback/providers/paypal.js +22 -0
- package/dist/manager/routes/payments/winback/providers/stripe.js +41 -0
- package/dist/manager/routes/payments/winback/providers/test.js +42 -0
- package/dist/manager/routes/restart/index.js +37 -0
- package/dist/manager/routes/special/electron-client/post.js +59 -0
- package/dist/manager/routes/test/authenticate/get.js +11 -0
- package/dist/manager/routes/test/health/get.js +8 -0
- package/dist/manager/routes/test/index.js +16 -0
- package/dist/manager/routes/test/lab/post.js +17 -0
- package/dist/manager/routes/test/redirect/get.js +27 -0
- package/dist/manager/routes/test/reset-account/post.js +79 -0
- package/dist/manager/routes/test/roster/get.js +40 -0
- package/dist/manager/routes/test/schema/post.js +20 -0
- package/dist/manager/routes/test/usage/post.js +44 -0
- package/dist/manager/routes/test/webhook/post.js +21 -0
- package/dist/manager/routes/user/api-keys/post.js +51 -0
- package/dist/manager/routes/user/connections/_context.js +194 -0
- package/dist/manager/routes/user/connections/_grant.js +247 -0
- package/dist/manager/routes/user/connections/_lease.js +184 -0
- package/dist/manager/routes/user/connections/_providers.js +191 -0
- package/dist/manager/routes/user/connections/_state.js +117 -0
- package/dist/manager/routes/user/connections/delete.js +55 -0
- package/dist/manager/routes/user/connections/get.js +167 -0
- package/dist/manager/routes/user/connections/post.js +370 -0
- package/dist/manager/routes/user/connections/providers/discord.js +41 -0
- package/dist/manager/routes/user/connections/providers/google.js +55 -0
- package/dist/manager/routes/user/connections/providers/kick.js +68 -0
- package/dist/manager/routes/user/connections/providers/spotify.js +40 -0
- package/dist/manager/routes/user/connections/providers/twitch.js +52 -0
- package/dist/manager/routes/user/data-request/delete.js +84 -0
- package/dist/manager/routes/user/data-request/get.js +229 -0
- package/dist/manager/routes/user/data-request/post.js +136 -0
- package/dist/manager/routes/user/delete.js +149 -0
- package/dist/manager/routes/user/feedback/post.js +81 -0
- package/dist/manager/routes/user/get.js +14 -0
- package/dist/manager/routes/user/orders/get.js +95 -0
- package/dist/manager/routes/user/sessions/delete.js +95 -0
- package/dist/manager/routes/user/sessions/get.js +40 -0
- package/dist/manager/routes/user/settings/validate/post.js +86 -0
- package/dist/manager/routes/user/signup/post.js +662 -0
- package/dist/manager/routes/user/subscription/get.js +77 -0
- package/dist/manager/routes/user/token/post.js +30 -0
- package/dist/manager/routes/verts/delete.js +43 -0
- package/dist/manager/routes/verts/get.js +49 -0
- package/dist/manager/routes/verts/post.js +61 -0
- package/dist/manager/routes/verts/put.js +75 -0
- package/dist/manager/routes/verts/redirect/get.js +36 -0
- package/dist/manager/routes/verts/serve/get.js +67 -0
- package/dist/manager/routes/verts/utils.js +436 -0
- package/dist/manager/schemas/admin/backup/post.js +8 -0
- package/dist/manager/schemas/admin/cron/post.js +8 -0
- package/dist/manager/schemas/admin/database/get.js +5 -0
- package/dist/manager/schemas/admin/database/post.js +6 -0
- package/dist/manager/schemas/admin/email/post.js +31 -0
- package/dist/manager/schemas/admin/firestore/get.js +5 -0
- package/dist/manager/schemas/admin/firestore/post.js +8 -0
- package/dist/manager/schemas/admin/firestore/query/post.js +5 -0
- package/dist/manager/schemas/admin/hook/post.js +8 -0
- package/dist/manager/schemas/admin/infer-contact/post.js +6 -0
- package/dist/manager/schemas/admin/notification/post.js +23 -0
- package/dist/manager/schemas/admin/payment/post.js +8 -0
- package/dist/manager/schemas/admin/post/post.js +23 -0
- package/dist/manager/schemas/admin/post/put.js +13 -0
- package/dist/manager/schemas/admin/repo/content/post.js +10 -0
- package/dist/manager/schemas/admin/stats/get.js +5 -0
- package/dist/manager/schemas/admin/users/disable/post.js +9 -0
- package/dist/manager/schemas/admin/users/list/get.js +10 -0
- package/dist/manager/schemas/admin/users/sync/post.js +7 -0
- package/dist/manager/schemas/brand/get.js +3 -0
- package/dist/manager/schemas/content/post/get.js +8 -0
- package/dist/manager/schemas/general/email/post.js +10 -0
- package/dist/manager/schemas/general/uuid/post.js +9 -0
- package/dist/manager/schemas/handler/post/post.js +13 -0
- package/dist/manager/schemas/health/get.js +3 -0
- package/dist/manager/schemas/marketing/campaign/delete.js +8 -0
- package/dist/manager/schemas/marketing/campaign/get.js +13 -0
- package/dist/manager/schemas/marketing/campaign/post.js +43 -0
- package/dist/manager/schemas/marketing/campaign/put.js +37 -0
- package/dist/manager/schemas/marketing/contact/delete.js +8 -0
- package/dist/manager/schemas/marketing/contact/post.js +14 -0
- package/dist/manager/schemas/marketing/contact/put.js +8 -0
- package/dist/manager/schemas/marketing/email-preferences/post.js +15 -0
- package/dist/manager/schemas/marketing/webhook/forward/post.js +8 -0
- package/dist/manager/schemas/marketing/webhook/post.js +7 -0
- package/dist/manager/schemas/payments/cancel/post.js +15 -0
- package/dist/manager/schemas/payments/discount/get.js +8 -0
- package/dist/manager/schemas/payments/dispute-alert/post.js +6 -0
- package/dist/manager/schemas/payments/intent/post.js +28 -0
- package/dist/manager/schemas/payments/plan/post.js +11 -0
- package/dist/manager/schemas/payments/portal/post.js +12 -0
- package/dist/manager/schemas/payments/refund/post.js +14 -0
- package/dist/manager/schemas/payments/trial-eligibility/get.js +7 -0
- package/dist/manager/schemas/payments/uncancel/post.js +9 -0
- package/dist/manager/schemas/payments/webhook/post.js +6 -0
- package/dist/manager/schemas/payments/winback/post.js +12 -0
- package/dist/manager/schemas/restart/index.js +5 -0
- package/dist/manager/schemas/special/electron-client/post.js +11 -0
- package/dist/manager/schemas/test/authenticate/get.js +3 -0
- package/dist/manager/schemas/test/health/get.js +3 -0
- package/dist/manager/schemas/test/index.js +5 -0
- package/dist/manager/schemas/test/lab/post.js +3 -0
- package/dist/manager/schemas/test/redirect/get.js +7 -0
- package/dist/manager/schemas/test/reset-account/post.js +3 -0
- package/dist/manager/schemas/test/roster/get.js +3 -0
- package/dist/manager/schemas/test/schema/post.js +70 -0
- package/dist/manager/schemas/test/usage/post.js +8 -0
- package/dist/manager/schemas/test/webhook/post.js +7 -0
- package/dist/manager/schemas/user/api-keys/post.js +6 -0
- package/dist/manager/schemas/user/connections/delete.js +8 -0
- package/dist/manager/schemas/user/connections/get.js +21 -0
- package/dist/manager/schemas/user/connections/post.js +12 -0
- package/dist/manager/schemas/user/data-request/delete.js +3 -0
- package/dist/manager/schemas/user/data-request/get.js +5 -0
- package/dist/manager/schemas/user/data-request/post.js +6 -0
- package/dist/manager/schemas/user/delete.js +6 -0
- package/dist/manager/schemas/user/feedback/post.js +8 -0
- package/dist/manager/schemas/user/get.js +3 -0
- package/dist/manager/schemas/user/orders/get.js +6 -0
- package/dist/manager/schemas/user/sessions/delete.js +6 -0
- package/dist/manager/schemas/user/sessions/get.js +6 -0
- package/dist/manager/schemas/user/settings/validate/post.js +8 -0
- package/dist/manager/schemas/user/signup/post.js +27 -0
- package/dist/manager/schemas/user/subscription/get.js +5 -0
- package/dist/manager/schemas/user/token/post.js +5 -0
- package/dist/manager/schemas/verts/delete.js +8 -0
- package/dist/manager/schemas/verts/get.js +9 -0
- package/dist/manager/schemas/verts/post.js +23 -0
- package/dist/manager/schemas/verts/put.js +20 -0
- package/dist/manager/schemas/verts/redirect/get.js +10 -0
- package/dist/manager/schemas/verts/serve/get.js +14 -0
- package/dist/manager/server-manager.js +69 -0
- package/dist/mcp/client.js +98 -0
- package/dist/mcp/handler.js +521 -0
- package/dist/mcp/index.js +157 -0
- package/dist/mcp/tools.js +555 -0
- package/dist/mcp/utils.js +108 -0
- package/dist/omega-bin.js +6 -0
- package/dist/require.js +3 -0
- package/dist/test/fixtures/firebase-project/.firebaserc +5 -0
- package/dist/test/fixtures/firebase-project/config/omega.json5 +131 -0
- package/dist/test/fixtures/firebase-project/database.rules.json +6 -0
- package/dist/test/fixtures/firebase-project/firebase.json +49 -0
- package/dist/test/fixtures/firebase-project/firestore.indexes.json +4 -0
- package/dist/test/fixtures/firebase-project/package.json +14 -0
- package/dist/test/fixtures/firebase-project/src/index.js +11 -0
- package/dist/test/fixtures/firebase-project/storage.rules +8 -0
- package/dist/test/parse-audit.js +25 -0
- package/dist/test/run-tests.js +90 -0
- package/dist/test/runner.js +982 -0
- package/dist/test/seed.js +242 -0
- package/dist/test/test-accounts.js +2660 -0
- package/dist/test/utils/assertions.js +189 -0
- package/dist/test/utils/email-capture.js +252 -0
- package/dist/test/utils/extended-mode-warning.js +11 -0
- package/dist/test/utils/firestore-rules-client.js +277 -0
- package/dist/test/utils/http-client.js +228 -0
- package/dist/test/utils/test-mode-file.js +192 -0
- package/dist/utils/merge-line-files.js +6 -0
- package/dist/utils/scaffold-defaults.js +71 -0
- package/dist/utils/test-lanes.js +62 -0
- package/dist/vendor/account/engine.js +182 -0
- package/dist/vendor/account/features.js +220 -0
- package/dist/vendor/account/index.js +53 -0
- package/dist/vendor/account/schema.js +272 -0
- package/dist/vendor/account/subscription.js +38 -0
- package/dist/vendor/analytics/adapters/ga4.js +26 -0
- package/dist/vendor/analytics/adapters/meta.js +26 -0
- package/dist/vendor/analytics/adapters/resolve.js +130 -0
- package/dist/vendor/analytics/adapters/tiktok.js +27 -0
- package/dist/vendor/analytics/catalog.js +908 -0
- package/dist/vendor/analytics/identity.js +136 -0
- package/dist/vendor/config/company.js +31 -0
- package/dist/vendor/config/defaults.js +173 -0
- package/dist/vendor/config/demo.js +18 -0
- package/dist/vendor/config/desktop-artifacts.js +110 -0
- package/dist/vendor/config/edit.js +769 -0
- package/dist/vendor/config/env-delivery.js +145 -0
- package/dist/vendor/config/env-rules.js +93 -0
- package/dist/vendor/config/env-schema.js +1078 -0
- package/dist/vendor/config/env.js +445 -0
- package/dist/vendor/config/hooks.js +97 -0
- package/dist/vendor/config/index.js +237 -0
- package/dist/vendor/config/instances.js +208 -0
- package/dist/vendor/config/load.js +490 -0
- package/dist/vendor/config/merge.js +68 -0
- package/dist/vendor/config/order.js +139 -0
- package/dist/vendor/config/ports.js +374 -0
- package/dist/vendor/config/providers.js +32 -0
- package/dist/vendor/config/repo.js +142 -0
- package/dist/vendor/config/retired-keys.js +430 -0
- package/dist/vendor/config/schema.js +1610 -0
- package/dist/vendor/config/secrets.js +50 -0
- package/dist/vendor/config/seed.js +34 -0
- package/dist/vendor/config/site-global.js +205 -0
- package/dist/vendor/config/validate.js +554 -0
- package/dist/vendor/config/winback.js +61 -0
- package/dist/vendor/devkit/attach-log-file.js +262 -0
- package/dist/vendor/devkit/bare-requires.js +153 -0
- package/dist/vendor/devkit/command-path.js +46 -0
- package/dist/vendor/devkit/defaults-engine.js +372 -0
- package/dist/vendor/devkit/deploy-record.js +180 -0
- package/dist/vendor/devkit/deploy.js +286 -0
- package/dist/vendor/devkit/license.js +155 -0
- package/dist/vendor/devkit/local-https.js +360 -0
- package/dist/vendor/devkit/local.js +1905 -0
- package/dist/vendor/devkit/logger.js +128 -0
- package/dist/vendor/devkit/merge-line-files.js +296 -0
- package/dist/vendor/devkit/npm-registry.js +52 -0
- package/dist/vendor/devkit/omega-bin.js +345 -0
- package/dist/vendor/devkit/parse-audit.js +74 -0
- package/dist/vendor/devkit/safe-install.js +18 -0
- package/dist/vendor/devkit/scaffold-guard.js +96 -0
- package/dist/vendor/devkit/stop-signals.js +28 -0
- package/dist/vendor/devkit/test/assert.js +120 -0
- package/dist/vendor/devkit/test/define-cases.js +104 -0
- package/dist/vendor/devkit/test/runner-core.js +554 -0
- package/dist/vendor/devkit/test/scope.js +162 -0
- package/dist/vendor/devkit/update.js +569 -0
- package/dist/vendor/monitoring/core.js +180 -0
- package/dist/vendor/monitoring/env.js +49 -0
- package/dist/vendor/monitoring/logger.js +39 -0
- package/dist/vendor/monitoring/node.js +72 -0
- package/docs/admin-post-route.md +57 -0
- package/docs/ai-library.md +171 -0
- package/docs/architecture.md +62 -0
- package/docs/audit.md +70 -0
- package/docs/auth-hooks.md +74 -0
- package/docs/build-system.md +65 -0
- package/docs/cdp-debugging.md +29 -0
- package/docs/cli-firestore-auth.md +85 -0
- package/docs/cli-logs.md +67 -0
- package/docs/cli-output.md +146 -0
- package/docs/code-patterns.md +77 -0
- package/docs/common-mistakes.md +12 -0
- package/docs/common-operations.md +60 -0
- package/docs/connections.md +212 -0
- package/docs/consent.md +362 -0
- package/docs/directory-structure.md +150 -0
- package/docs/email-system.md +459 -0
- package/docs/environment-detection.md +93 -0
- package/docs/file-naming.md +10 -0
- package/docs/firestore.md +134 -0
- package/docs/ghostii.md +240 -0
- package/docs/index.md +299 -0
- package/docs/key-files.md +37 -0
- package/docs/logging.md +60 -0
- package/docs/marketing-campaigns.md +407 -0
- package/docs/marketing-fields.md +25 -0
- package/docs/mcp.md +222 -0
- package/docs/migration.md +129 -0
- package/docs/payment-system.md +856 -0
- package/docs/paypal-sandbox-qa.md +105 -0
- package/docs/response-headers.md +9 -0
- package/docs/routes.md +211 -0
- package/docs/sanitization.md +71 -0
- package/docs/schemas.md +163 -0
- package/docs/shared/agent-docs.md +89 -0
- package/docs/shared/analytics.md +612 -0
- package/docs/shared/brands.md +51 -0
- package/docs/shared/breaking-changes.md +497 -0
- package/docs/shared/config.md +1387 -0
- package/docs/shared/deploys.md +215 -0
- package/docs/shared/icons.md +201 -0
- package/docs/shared/local-dev.md +147 -0
- package/docs/shared/logging.md +202 -0
- package/docs/shared/monitoring.md +153 -0
- package/docs/shared/publishing.md +183 -0
- package/docs/shared/rulings.md +34 -0
- package/docs/shared/testing.md +147 -0
- package/docs/shared/theming.md +604 -0
- package/docs/shared/translation.md +291 -0
- package/docs/shared/updates.md +61 -0
- package/docs/stripe-webhook-forwarding.md +20 -0
- package/docs/test-boot-layer.md +67 -0
- package/docs/test-framework.md +583 -0
- package/docs/usage-rate-limiting.md +121 -0
- package/docs/verts.md +29 -0
- package/package.json +143 -0
- package/templates/config/omega.json5 +322 -0
- package/templates/database.rules.json +82 -0
- package/templates/firebase.json +67 -0
- package/templates/firestore.framework.rules +191 -0
- package/templates/firestore.indexes.json +4 -0
- package/templates/firestore.rules +59 -0
- package/templates/index.js +12 -0
- package/templates/public/404.html +26 -0
- package/templates/public/index.html +24 -0
- package/templates/remoteconfig.template.json +1 -0
- package/templates/storage-lifecycle-config-1-day.json +9 -0
- package/templates/storage-lifecycle-config-30-days.json +9 -0
- package/templates/storage.rules +11 -0
- package/test/_init/accounts-validation.js +58 -0
- package/test/ai/tools-live.test.js +171 -0
- package/test/analytics/conversion-delivery.test.js +1013 -0
- package/test/analytics/match-normalization.test.js +238 -0
- package/test/analytics/signup-conversion.test.js +135 -0
- package/test/boot/cli-dispatch.test.js +142 -0
- package/test/boot/defaults-scaffold.test.js +248 -0
- package/test/boot/deploy-staging.test.js +446 -0
- package/test/boot/disposable-domains.test.js +154 -0
- package/test/boot/emulator-boots.test.js +39 -0
- package/test/boot/emulator-port-preflight.test.js +126 -0
- package/test/boot/emulator-ready-timeout.test.js +46 -0
- package/test/boot/project-id-refresh.test.js +73 -0
- package/test/boot/suite-portability.test.js +278 -0
- package/test/boot/update-command.test.js +63 -0
- package/test/cli/cross-platform.test.js +168 -0
- package/test/cli/custom-project-type.test.js +426 -0
- package/test/cli/deploy-license-env.test.js +100 -0
- package/test/cli/emulator-adoption.test.js +254 -0
- package/test/cli/emulator-orphans.test.js +658 -0
- package/test/cli/emulator-ownership.test.js +177 -0
- package/test/cli/emulator-port-retry.test.js +395 -0
- package/test/cli/emulator-shutdown.test.js +788 -0
- package/test/cli/emulator-stale-reap.test.js +574 -0
- package/test/cli/ensure-target.test.js +325 -0
- package/test/cli/flags.test.js +64 -0
- package/test/cli/https-trust.test.js +38 -0
- package/test/cli/install-update-dispatch.test.js +47 -0
- package/test/cli/lane-environments.test.js +159 -0
- package/test/cli/marketing-campaigns-seeded.test.js +194 -0
- package/test/cli/migrate-bare-requires.test.js +128 -0
- package/test/cli/migrate-markers.test.js +530 -0
- package/test/cli/required-indexes.test.js +64 -0
- package/test/cli/rules-compile.test.js +622 -0
- package/test/cli/rules-migration-deferral.test.js +259 -0
- package/test/cli/rules-version.test.js +104 -0
- package/test/cli/setup-load-files.test.js +66 -0
- package/test/cli/setup-offline-mode.test.js +276 -0
- package/test/cli/setup-retired.test.js +64 -0
- package/test/cli/setup-shared-project-indexes.test.js +262 -0
- package/test/cli/setup-tests-requires.test.js +45 -0
- package/test/cli/stage-env-compose.test.js +316 -0
- package/test/cli/stripe-live-lane.test.js +303 -0
- package/test/cli/target.test.js +182 -0
- package/test/cli/templates.test.js +66 -0
- package/test/cli/test-runner-env.test.js +115 -0
- package/test/cli/test-stack-shutdown.test.js +275 -0
- package/test/cli/test-target-no-match.test.js +128 -0
- package/test/cli/verb-logs.test.js +118 -0
- package/test/cli/version-dispatch.test.js +39 -0
- package/test/content/blog-generate.test.js +164 -0
- package/test/email/campaign-config-fault.test.js +376 -0
- package/test/email/campaign-cron-pipeline.test.js +536 -0
- package/test/email/campaign-send.test.js +47 -0
- package/test/email/consent-lifecycle.test.js +258 -0
- package/test/email/content-html-policy.test.js +270 -0
- package/test/email/feedback-and-plain-send.test.js +54 -0
- package/test/email/fixtures/clean.json +30 -0
- package/test/email/fixtures/editorial.json +30 -0
- package/test/email/fixtures/field-report.json +53 -0
- package/test/email/identity.test.js +321 -0
- package/test/email/marketing/consent-gate.test.js +265 -0
- package/test/email/marketing/custom-fields-catalog.test.js +259 -0
- package/test/email/marketing/prune-per-provider.test.js +762 -0
- package/test/email/marketing/remove-log-privacy.test.js +225 -0
- package/test/email/marketing-lifecycle.test.js +139 -0
- package/test/email/newsletter-generate.test.js +853 -0
- package/test/email/newsletter-svg-tokens.test.js +51 -0
- package/test/email/newsletter-templates.test.js +492 -0
- package/test/email/order-one-time-cta.test.js +97 -0
- package/test/email/render-content.test.js +248 -0
- package/test/email/safe-url.test.js +0 -0
- package/test/email/sanitize-images.test.js +66 -0
- package/test/email/send-log-privacy.test.js +107 -0
- package/test/email/templates.test.js +288 -0
- package/test/email/testing-capture.test.js +260 -0
- package/test/email/transactional-send.test.js +36 -0
- package/test/email/transactional.test.js +562 -0
- package/test/email/unsubscribe-groups.test.js +155 -0
- package/test/email/unsubscribe-key.test.js +91 -0
- package/test/email/validation-cases.test.js +152 -0
- package/test/email/validation.test.js +746 -0
- package/test/events/auth-delete-conversion.test.js +138 -0
- package/test/events/auth-delete-race.test.js +211 -0
- package/test/events/auth-on-create-log.test.js +164 -0
- package/test/events/auth-signup-conversion.test.js +141 -0
- package/test/events/auth-signup-limit.test.js +142 -0
- package/test/events/auth-trigger-log-privacy.test.js +256 -0
- package/test/events/cron-job-doc-shape.test.js +101 -0
- package/test/events/cron-reset-usage.test.js +116 -0
- package/test/events/notification-conversion.test.js +182 -0
- package/test/events/payments/_webhook-harness.js +307 -0
- package/test/events/payments/abandoned-cart-activity.test.js +135 -0
- package/test/events/payments/analytics-payment-events.test.js +945 -0
- package/test/events/payments/dispute-email-status.test.js +55 -0
- package/test/events/payments/journey-payments-abandoned.test.js +126 -0
- package/test/events/payments/journey-payments-cancel-endpoint.test.js +102 -0
- package/test/events/payments/journey-payments-cancel-no-order.test.js +76 -0
- package/test/events/payments/journey-payments-cancel.test.js +184 -0
- package/test/events/payments/journey-payments-decline.test.js +225 -0
- package/test/events/payments/journey-payments-discount.test.js +91 -0
- package/test/events/payments/journey-payments-dispute.test.js +190 -0
- package/test/events/payments/journey-payments-failure.test.js +148 -0
- package/test/events/payments/journey-payments-legacy-product.test.js +151 -0
- package/test/events/payments/journey-payments-one-time-decline.test.js +127 -0
- package/test/events/payments/journey-payments-one-time-failure.test.js +113 -0
- package/test/events/payments/journey-payments-one-time-refund.test.js +186 -0
- package/test/events/payments/journey-payments-one-time.test.js +175 -0
- package/test/events/payments/journey-payments-plan-change.test.js +146 -0
- package/test/events/payments/journey-payments-plan-switch-trial.test.js +161 -0
- package/test/events/payments/journey-payments-plan-switch.test.js +182 -0
- package/test/events/payments/journey-payments-refund-no-order.test.js +76 -0
- package/test/events/payments/journey-payments-refund-webhook.test.js +225 -0
- package/test/events/payments/journey-payments-suspend.test.js +183 -0
- package/test/events/payments/journey-payments-trial-cancel.test.js +132 -0
- package/test/events/payments/journey-payments-trial.test.js +173 -0
- package/test/events/payments/journey-payments-uid-resolution.test.js +134 -0
- package/test/events/payments/journey-payments-uncancel.test.js +157 -0
- package/test/events/payments/journey-payments-upgrade.test.js +137 -0
- package/test/events/payments/journey-payments-winback-decline.test.js +171 -0
- package/test/events/payments/journey-payments-winback.test.js +195 -0
- package/test/events/payments/paypal-expiry-cron.test.js +166 -0
- package/test/events/payments/purchase-failed-handler.test.js +80 -0
- package/test/events/payments/purchase-refunded-handler.test.js +108 -0
- package/test/events/payments/test-processor-doc-shape.test.js +162 -0
- package/test/events/payments/transition-order-emails.test.js +185 -0
- package/test/events/payments/transition-promo-lines.test.js +192 -0
- package/test/events/payments/transitions-detect.test.js +767 -0
- package/test/events/payments/trial-lapse-sweep-staleness.test.js +173 -0
- package/test/events/payments/trial-lapse-sweep.test.js +359 -0
- package/test/events/payments/webhook-atomic-writes.test.js +69 -0
- package/test/events/payments/webhook-chargebee-unreachable.test.js +106 -0
- package/test/events/payments/webhook-discount-clear.test.js +189 -0
- package/test/events/payments/webhook-failure-intent.test.js +93 -0
- package/test/events/payments/webhook-hosted-page-uid-trust.test.js +212 -0
- package/test/events/payments/webhook-ordering.test.js +326 -0
- package/test/events/payments/webhook-provider-lookup-trust.test.js +206 -0
- package/test/events/payments/webhook-refund-amount-trust.test.js +223 -0
- package/test/events/payments/webhook-refund-envelope-shape.test.js +148 -0
- package/test/events/payments/webhook-refund-linkage-trust.test.js +404 -0
- package/test/events/payments/webhook-refund-transaction-fallback.test.js +184 -0
- package/test/events/payments/webhook-refund-without-order.test.js +170 -0
- package/test/events/payments/webhook-refusal-reporting.test.js +194 -0
- package/test/events/payments/webhook-refused-intent.test.js +142 -0
- package/test/events/payments/webhook-retry-sweep.test.js +252 -0
- package/test/events/payments/webhook-transition-claim.test.js +389 -0
- package/test/events/payments/webhook-uid-trust.test.js +203 -0
- package/test/events/payments/webhook-user-without-auth.test.js +161 -0
- package/test/fixtures/chargebee/invoice-one-time.json +27 -0
- package/test/fixtures/chargebee/subscription-active.json +44 -0
- package/test/fixtures/chargebee/subscription-cancelled.json +42 -0
- package/test/fixtures/chargebee/subscription-in-trial.json +41 -0
- package/test/fixtures/chargebee/subscription-legacy-plan.json +41 -0
- package/test/fixtures/chargebee/subscription-non-renewing.json +41 -0
- package/test/fixtures/chargebee/subscription-paused.json +42 -0
- package/test/fixtures/chargebee/webhook-payment-failed.json +51 -0
- package/test/fixtures/chargebee/webhook-subscription-created.json +47 -0
- package/test/fixtures/coinbase/charge-confirmed.json +50 -0
- package/test/fixtures/coinbase/charge-failed.json +34 -0
- package/test/fixtures/coinbase/charge-pending.json +34 -0
- package/test/fixtures/migrate/ported-route.js.txt +11 -0
- package/test/fixtures/paypal/capture-completed.json +51 -0
- package/test/fixtures/paypal/capture-refunded.json +43 -0
- package/test/fixtures/paypal/order-approved.json +62 -0
- package/test/fixtures/paypal/order-completed.json +110 -0
- package/test/fixtures/paypal/sale-refunded.json +38 -0
- package/test/fixtures/paypal/subscription-active.json +76 -0
- package/test/fixtures/paypal/subscription-cancelled.json +50 -0
- package/test/fixtures/paypal/subscription-suspended.json +65 -0
- package/test/fixtures/stripe/checkout-session-completed.json +130 -0
- package/test/fixtures/stripe/invoice-payment-failed.json +148 -0
- package/test/fixtures/stripe/invoice-subscription-payment-failed.json +28 -0
- package/test/fixtures/stripe/invoice-subscription-payment-succeeded.json +28 -0
- package/test/fixtures/stripe/subscription-active.json +161 -0
- package/test/fixtures/stripe/subscription-canceled.json +161 -0
- package/test/fixtures/stripe/subscription-trialing.json +161 -0
- package/test/helpers/_shared-config.js +15 -0
- package/test/helpers/ai-request-payload.test.js +619 -0
- package/test/helpers/ai-schema-resolve.test.js +125 -0
- package/test/helpers/ai-test-provider.test.js +227 -0
- package/test/helpers/ai-token-accounting.test.js +150 -0
- package/test/helpers/ai-tools-format.test.js +384 -0
- package/test/helpers/analytics-no-id-notice.test.js +146 -0
- package/test/helpers/analytics-user-data.test.js +194 -0
- package/test/helpers/api-manager.test.js +311 -0
- package/test/helpers/backend-router.test.js +136 -0
- package/test/helpers/content/blog-auto-publisher.test.js +482 -0
- package/test/helpers/content/feed-parser.test.js +529 -0
- package/test/helpers/content/ghostii-blocks.test.js +135 -0
- package/test/helpers/content/ghostii-feed-integration.test.js +405 -0
- package/test/helpers/content/ghostii-write-article.test.js +244 -0
- package/test/helpers/dev-only-routes.test.js +225 -0
- package/test/helpers/env-reader.test.js +362 -0
- package/test/helpers/environment.test.js +263 -0
- package/test/helpers/event-middleware.test.js +407 -0
- package/test/helpers/infer-contact.test.js +157 -0
- package/test/helpers/lane-url.test.js +90 -0
- package/test/helpers/merge-line-files.test.js +272 -0
- package/test/helpers/metadata.test.js +122 -0
- package/test/helpers/middleware-request-log.test.js +134 -0
- package/test/helpers/middleware-user-log.test.js +124 -0
- package/test/helpers/payment/chargebee/parse-webhook.test.js +490 -0
- package/test/helpers/payment/chargebee/refund-details.test.js +198 -0
- package/test/helpers/payment/chargebee/to-unified-one-time.test.js +148 -0
- package/test/helpers/payment/chargebee/to-unified-subscription.test.js +649 -0
- package/test/helpers/payment/coinbase/create-intent.test.js +247 -0
- package/test/helpers/payment/coinbase/parse-webhook.test.js +195 -0
- package/test/helpers/payment/coinbase/refund-unsupported.test.js +141 -0
- package/test/helpers/payment/coinbase/to-unified-one-time.test.js +201 -0
- package/test/helpers/payment/discount-codes.test.js +141 -0
- package/test/helpers/payment/extract-resource.test.js +113 -0
- package/test/helpers/payment/fetch-failure.test.js +215 -0
- package/test/helpers/payment/license-gate.test.js +108 -0
- package/test/helpers/payment/order-id.test.js +99 -0
- package/test/helpers/payment/paypal/create-intent.test.js +382 -0
- package/test/helpers/payment/paypal/fetch-capture.test.js +123 -0
- package/test/helpers/payment/paypal/fetch-sale.test.js +183 -0
- package/test/helpers/payment/paypal/parse-webhook.test.js +678 -0
- package/test/helpers/payment/paypal/refund-details.test.js +202 -0
- package/test/helpers/payment/paypal/resolve-plan-id.test.js +108 -0
- package/test/helpers/payment/paypal/switch-plan.test.js +92 -0
- package/test/helpers/payment/paypal/to-unified-one-time.test.js +383 -0
- package/test/helpers/payment/paypal/to-unified-subscription.test.js +884 -0
- package/test/helpers/payment/stripe/fetch-charge.test.js +147 -0
- package/test/helpers/payment/stripe/parse-webhook.test.js +448 -0
- package/test/helpers/payment/stripe/refund-details.test.js +147 -0
- package/test/helpers/payment/stripe/to-unified-one-time.test.js +307 -0
- package/test/helpers/payment/stripe/to-unified-subscription.test.js +709 -0
- package/test/helpers/persona-domain.test.js +87 -0
- package/test/helpers/recaptcha.test.js +166 -0
- package/test/helpers/resolved-config.test.js +106 -0
- package/test/helpers/response-log-redaction.test.js +262 -0
- package/test/helpers/roles.test.js +155 -0
- package/test/helpers/route-context-debug-gate.test.js +118 -0
- package/test/helpers/route-context-logging.test.js +214 -0
- package/test/helpers/route-context.test.js +129 -0
- package/test/helpers/safe-compare.test.js +114 -0
- package/test/helpers/sanitize.test.js +223 -0
- package/test/helpers/schema-engine.test.js +537 -0
- package/test/helpers/schema-zod.test.js +554 -0
- package/test/helpers/seed-accounts-load.test.js +163 -0
- package/test/helpers/seed-google-personas.test.js +114 -0
- package/test/helpers/seeded-personas.test.js +823 -0
- package/test/helpers/settings.test.js +292 -0
- package/test/helpers/setup-engines-pin.test.js +68 -0
- package/test/helpers/setup-manifest-sync.test.js +116 -0
- package/test/helpers/slugify.test.js +395 -0
- package/test/helpers/storage.test.js +195 -0
- package/test/helpers/test-banner-latch.test.js +139 -0
- package/test/helpers/usage-consume.test.js +460 -0
- package/test/helpers/usage-log-privacy.test.js +121 -0
- package/test/helpers/user-doc-heal.test.js +540 -0
- package/test/helpers/user.test.js +771 -0
- package/test/helpers/webhook-forward.test.js +419 -0
- package/test/helpers/wipe-auth-project.test.js +143 -0
- package/test/mcp/discovery.test.js +52 -0
- package/test/mcp/oauth.test.js +160 -0
- package/test/mcp/protocol.test.js +278 -0
- package/test/mcp/roles.test.js +203 -0
- package/test/mcp/utils.test.js +245 -0
- package/test/notification/identity.test.js +155 -0
- package/test/routes/admin/create-post.test.js +362 -0
- package/test/routes/admin/database.test.js +133 -0
- package/test/routes/admin/deduplicate-image-alts.test.js +191 -0
- package/test/routes/admin/email-content-html.test.js +58 -0
- package/test/routes/admin/email-request-log.test.js +86 -0
- package/test/routes/admin/email.test.js +116 -0
- package/test/routes/admin/firestore-query.test.js +206 -0
- package/test/routes/admin/firestore.test.js +129 -0
- package/test/routes/admin/infer-contact.test.js +220 -0
- package/test/routes/admin/notification.test.js +199 -0
- package/test/routes/admin/post-convert-image.test.js +159 -0
- package/test/routes/admin/post-deploy-flag.test.js +81 -0
- package/test/routes/admin/post-download-error.test.js +90 -0
- package/test/routes/admin/post-resize-image.test.js +185 -0
- package/test/routes/admin/post.test.js +369 -0
- package/test/routes/admin/repo-content.test.js +223 -0
- package/test/routes/admin/stats.test.js +114 -0
- package/test/routes/admin/users-disable.test.js +63 -0
- package/test/routes/admin/users-list.test.js +71 -0
- package/test/routes/content/post.test.js +60 -0
- package/test/routes/general/uuid.test.js +133 -0
- package/test/routes/health.test.js +110 -0
- package/test/routes/marketing/campaign.test.js +184 -0
- package/test/routes/marketing/contact.test.js +416 -0
- package/test/routes/marketing/email-preferences.test.js +293 -0
- package/test/routes/marketing/push-send.test.js +34 -0
- package/test/routes/marketing/webhook-forward.test.js +63 -0
- package/test/routes/marketing/webhook.test.js +641 -0
- package/test/routes/payments/_route-harness.js +145 -0
- package/test/routes/payments/cancel-provider-errors.test.js +227 -0
- package/test/routes/payments/cancel-skip-guards.test.js +126 -0
- package/test/routes/payments/cancel-trialing.test.js +428 -0
- package/test/routes/payments/cancel.test.js +165 -0
- package/test/routes/payments/dedup-race.test.js +186 -0
- package/test/routes/payments/discount.test.js +82 -0
- package/test/routes/payments/dispute-alert.test.js +324 -0
- package/test/routes/payments/intent-discount-amounts.test.js +550 -0
- package/test/routes/payments/intent-discount-coupons.test.js +293 -0
- package/test/routes/payments/intent-one-time-metadata.test.js +122 -0
- package/test/routes/payments/intent-purchaser-guard.test.js +139 -0
- package/test/routes/payments/intent-zero-total.test.js +260 -0
- package/test/routes/payments/intent.test.js +413 -0
- package/test/routes/payments/plan.test.js +367 -0
- package/test/routes/payments/portal-return-url.test.js +107 -0
- package/test/routes/payments/portal.test.js +94 -0
- package/test/routes/payments/refund-one-time.test.js +254 -0
- package/test/routes/payments/refund-paypal-proration.test.js +190 -0
- package/test/routes/payments/refund.test.js +181 -0
- package/test/routes/payments/trial-eligibility.test.js +73 -0
- package/test/routes/payments/uncancel.test.js +270 -0
- package/test/routes/payments/webhook-stripe-invoice.test.js +129 -0
- package/test/routes/payments/webhook-stripe-refund-one-time.test.js +130 -0
- package/test/routes/payments/webhook-test-provider.test.js +156 -0
- package/test/routes/payments/webhook.test.js +115 -0
- package/test/routes/payments/winback-stripe-coupon.test.js +126 -0
- package/test/routes/payments/winback.test.js +597 -0
- package/test/routes/test/authenticate.test.js +79 -0
- package/test/routes/test/redirect.test.js +66 -0
- package/test/routes/test/reset-account.test.js +126 -0
- package/test/routes/test/roster.test.js +101 -0
- package/test/routes/test/schema.test.js +556 -0
- package/test/routes/test/usage.test.js +374 -0
- package/test/routes/user/api-keys.test.js +158 -0
- package/test/routes/user/connections-grant.test.js +759 -0
- package/test/routes/user/connections-identity.test.js +260 -0
- package/test/routes/user/connections-log-privacy.test.js +206 -0
- package/test/routes/user/connections-refresh-lease.test.js +696 -0
- package/test/routes/user/connections-return.test.js +261 -0
- package/test/routes/user/connections-uid.test.js +516 -0
- package/test/routes/user/delete.test.js +138 -0
- package/test/routes/user/feedback.test.js +106 -0
- package/test/routes/user/orders.test.js +233 -0
- package/test/routes/user/sessions.test.js +231 -0
- package/test/routes/user/settings-validate.test.js +84 -0
- package/test/routes/user/signup-emails.test.js +113 -0
- package/test/routes/user/signup-location.test.js +84 -0
- package/test/routes/user/signup-log-privacy.test.js +112 -0
- package/test/routes/user/signup.test.js +579 -0
- package/test/routes/user/subscription.test.js +101 -0
- package/test/routes/user/token.test.js +111 -0
- package/test/routes/user/user.test.js +158 -0
- package/test/routes/verts/cache.test.js +78 -0
- package/test/routes/verts/click-destination.test.js +76 -0
- package/test/routes/verts/crud.test.js +194 -0
- package/test/routes/verts/redirect.test.js +147 -0
- package/test/routes/verts/selection.test.js +237 -0
- package/test/routes/verts/serve.test.js +185 -0
- package/test/routes/verts/unit-document.test.js +117 -0
- package/test/rules/_environment.js +66 -0
- package/test/rules/brand-merge.test.js +195 -0
- package/test/rules/field-helpers.test.js +309 -0
- package/test/rules/notifications.test.js +577 -0
- package/test/rules/payments-carts.test.js +406 -0
- package/test/rules/sessions.test.js +170 -0
- package/test/rules/user.test.js +517 -0
- package/test/rules/verts.test.js +101 -0
- package/test/security/fetch-log-secrets.test.js +124 -0
- package/test/security/primitives.test.js +105 -0
- package/test/security/repo-pinning.test.js +77 -0
- package/test/stripe-live/subscription-lifecycle.test.js +141 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Predefined fixture for the `field-report` template. Loaded via NEWSLETTER_FIXTURE=field-report. Wire-service content shape: tldr + dateline + dispatches[{kicker, headline, byline, location, lede, dispatch, dataPoints, image_prompt}].",
|
|
3
|
+
"subject": "LinkedIn tightens identity — operators document everything",
|
|
4
|
+
"preheader": "Three filings from this week's platform front lines.",
|
|
5
|
+
"summary": "Wire from the platform front: LinkedIn is rolling identity verification across every business profile, YouTube is piloting upload-time attribution metadata, and the operators with clean documentation are outrunning everyone else.",
|
|
6
|
+
"tags": ["linkedin", "youtube", "platform-policy", "verification", "operator-playbook"],
|
|
7
|
+
"tldr": "LinkedIn is rolling out verified-account scrutiny across every business profile. Operators with paper trails will outrun the rest. Documentation is the new growth lever.",
|
|
8
|
+
"dateline": "OAKLAND",
|
|
9
|
+
"signoff": "— Stay sharp,\nThe Somiibo Desk",
|
|
10
|
+
"citations": [
|
|
11
|
+
{ "note": "LinkedIn flagged 12,000 impersonation attempts in the verified-profile beta.", "source": "Reported by LinkedIn product team, May 2026" },
|
|
12
|
+
{ "note": "Operator playbook adoption up 38% week-over-week in Q2.", "source": "Per platform analytics, May 2026" }
|
|
13
|
+
],
|
|
14
|
+
"dispatches": [
|
|
15
|
+
{
|
|
16
|
+
"kicker": "LEAD DISPATCH",
|
|
17
|
+
"headline": "LinkedIn ships verified-profile gates for every business account",
|
|
18
|
+
"byline": "Filed by The Somiibo platform desk",
|
|
19
|
+
"location": "OAKLAND",
|
|
20
|
+
"lede": "A wave of identity-verification gates is rolling out across LinkedIn business profiles this week — and the platform is not asking politely.",
|
|
21
|
+
"dispatch": "LinkedIn now requires verified identity attestations on any business profile claiming more than 500 followers. The rollout is fast and uneven: some accounts hit the gate inside two days of profile activity, others sit unchallenged for weeks. The pattern that matters is this — accounts with documented attribution histories sail through verification in under twelve hours. Accounts without get queued. The practical implication is to lock down your attribution log this week, not next.",
|
|
22
|
+
"dataPoints": [
|
|
23
|
+
{ "label": "PROFILES FLAGGED", "value": "12.4K" },
|
|
24
|
+
{ "label": "AVG REVIEW TIME", "value": "14HR" },
|
|
25
|
+
{ "label": "WoW APPROVAL", "value": "+38%" }
|
|
26
|
+
],
|
|
27
|
+
"image_prompt": "Abstract geometric illustration of a verification checkmark inside a layered profile card."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"kicker": "FIELD NOTES",
|
|
31
|
+
"headline": "Documentation is the new operator moat",
|
|
32
|
+
"byline": "Filed by The Somiibo growth desk",
|
|
33
|
+
"location": "REMOTE",
|
|
34
|
+
"lede": "The teams surviving this round of platform scrutiny share one habit: they write everything down.",
|
|
35
|
+
"dispatch": "Operator playbooks — once dismissed as overhead — are now the difference between an account that recovers from a flag and one that gets permanently restricted. The teams already running on documented processes recover in days. The ones without burn weeks negotiating with support queues. Treat your playbook as a compliance artifact, not a knowledge-management nice-to-have.",
|
|
36
|
+
"dataPoints": [
|
|
37
|
+
{ "label": "RECOVERY (DOCUMENTED)", "value": "4D" },
|
|
38
|
+
{ "label": "RECOVERY (UNDOC)", "value": "21D" }
|
|
39
|
+
],
|
|
40
|
+
"image_prompt": "Stack of geometric document layers casting clean shadows on a flat surface."
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"kicker": "WATCH",
|
|
44
|
+
"headline": "YouTube tests creator-attribution metadata on uploads",
|
|
45
|
+
"byline": "Filed by The Somiibo signals desk",
|
|
46
|
+
"location": "NEW YORK",
|
|
47
|
+
"lede": "A small pilot suggests YouTube will soon ask creators to declare automated tooling and cross-posting workflows at upload time.",
|
|
48
|
+
"dispatch": "A subset of channels saw a new upload checkbox this week asking whether content was assisted by automation. The checkbox is optional today. Reading the room: it will not stay optional. Creators with clear internal workflows already labeled will adapt in an afternoon. Everyone else will spend a quarter retrofitting.",
|
|
49
|
+
"dataPoints": [],
|
|
50
|
+
"image_prompt": "Minimalist play button morphing into a label tag, flat geometric style."
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email identity test — every human/company identity in outbound email comes from
|
|
3
|
+
* config, and a missing one fails LOUDLY.
|
|
4
|
+
*
|
|
5
|
+
* The framework used to ship its author's name, headshot, personal links and the
|
|
6
|
+
* parent company's wordmark/BCC addresses as hardcoded fallbacks, so any brand that
|
|
7
|
+
* had not configured its own identity silently mailed its users as someone else.
|
|
8
|
+
* These checks pin the replacement: config-driven, or a thrown error — never a
|
|
9
|
+
* substituted identity.
|
|
10
|
+
*
|
|
11
|
+
* Plain-node unit test (no emulator, no network).
|
|
12
|
+
*/
|
|
13
|
+
const assert = require('node:assert');
|
|
14
|
+
const { resolvePerson, resolveSignoff } = require('../../dist/manager/libraries/email/prepare.js');
|
|
15
|
+
const { footer } = require('../../dist/manager/libraries/email/generators/lib/templates/base.js');
|
|
16
|
+
const feedbackTemplate = require('../../dist/manager/libraries/email/generators/lib/templates/feedback.js');
|
|
17
|
+
const defineCases = require('../../dist/vendor/devkit/test/define-cases.js');
|
|
18
|
+
|
|
19
|
+
// The identity the framework used to hardcode. Nothing may ever emit these again.
|
|
20
|
+
const FRAMEWORK_IDENTITY = /Ian Wiedenman|ianwiedenman|ianwieds|ITW Creative Works|itwcreativeworks/i;
|
|
21
|
+
|
|
22
|
+
const brandWithPerson = {
|
|
23
|
+
name: 'Acme',
|
|
24
|
+
company: 'Acme Holdings Inc',
|
|
25
|
+
url: 'https://acme.example',
|
|
26
|
+
contact: {
|
|
27
|
+
email: 'support@acme.example',
|
|
28
|
+
person: {
|
|
29
|
+
name: 'Jane Doe, CEO',
|
|
30
|
+
image: 'https://acme.example/jane.jpg',
|
|
31
|
+
url: 'https://jane.example',
|
|
32
|
+
urlText: '@janedoe',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
images: { companyWordmark: 'https://acme.example/holdings-wordmark.png' },
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const brandWithoutPerson = { name: 'Acme', contact: { email: 'support@acme.example' } };
|
|
39
|
+
|
|
40
|
+
// The audit-BCC checks go through the REAL transactional build — a resolver-only test
|
|
41
|
+
// would still pass if build() stopped reading the config. Each build runs once and is
|
|
42
|
+
// shared by its assertions.
|
|
43
|
+
function buildWith(brand, settings) {
|
|
44
|
+
process.env.UNSUBSCRIBE_HMAC_KEY = process.env.UNSUBSCRIBE_HMAC_KEY || 'test-key';
|
|
45
|
+
|
|
46
|
+
const Transactional = require('../../dist/manager/libraries/email/transactional/index.js');
|
|
47
|
+
const Manager = {
|
|
48
|
+
config: {
|
|
49
|
+
brand: { id: 'acme', url: 'https://acme.example', images: {}, ...brand },
|
|
50
|
+
// The account's unsubscribe group ids (#649) — every send resolves one from config
|
|
51
|
+
marketing: { campaigns: { providers: { sendgrid: { groups: { orders: 900001, hello: 900002, account: 900003, marketing: 900004, security: 900005, newsletter: 900006, internal: 900007 } } } } },
|
|
52
|
+
},
|
|
53
|
+
project: { websiteUrl: 'https://acme.example' },
|
|
54
|
+
libraries: { admin: {} },
|
|
55
|
+
User: () => ({ properties: {} }),
|
|
56
|
+
};
|
|
57
|
+
const ctx = { Manager, log: () => {}, error: () => {} };
|
|
58
|
+
|
|
59
|
+
return new Transactional(ctx).build({
|
|
60
|
+
to: 'user@acme.example',
|
|
61
|
+
subject: 'Hi',
|
|
62
|
+
template: 'card',
|
|
63
|
+
copy: true,
|
|
64
|
+
...settings,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let configuredBuild;
|
|
69
|
+
const buildConfigured = () => (configuredBuild = configuredBuild || buildWith({
|
|
70
|
+
...brandWithPerson,
|
|
71
|
+
contact: {
|
|
72
|
+
...brandWithPerson.contact,
|
|
73
|
+
carbonCopy: [
|
|
74
|
+
{ email: 'audit@acme.example', name: 'Acme Audit' },
|
|
75
|
+
{ email: 'archive@acme.example' },
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
}));
|
|
79
|
+
|
|
80
|
+
let unconfiguredBuild;
|
|
81
|
+
const buildUnconfigured = () => (unconfiguredBuild = unconfiguredBuild || buildWith(brandWithPerson));
|
|
82
|
+
|
|
83
|
+
let malformedBuild;
|
|
84
|
+
const buildMalformed = () => (malformedBuild = malformedBuild || buildWith({
|
|
85
|
+
...brandWithPerson,
|
|
86
|
+
contact: { ...brandWithPerson.contact, carbonCopy: [{ name: 'No Address' }] },
|
|
87
|
+
}).catch((error) => error));
|
|
88
|
+
|
|
89
|
+
module.exports = defineCases({
|
|
90
|
+
description: 'Email identity (person, company, audit BCCs come from config)',
|
|
91
|
+
type: 'group',
|
|
92
|
+
tests: [
|
|
93
|
+
// ---------- Personal signoff: config-driven ----------
|
|
94
|
+
|
|
95
|
+
{
|
|
96
|
+
name: 'personal signoff is filled from brand.contact.person',
|
|
97
|
+
|
|
98
|
+
run() {
|
|
99
|
+
const out = resolveSignoff({ type: 'personal' }, brandWithPerson);
|
|
100
|
+
|
|
101
|
+
assert.equal(out.name, 'Jane Doe, CEO');
|
|
102
|
+
assert.equal(out.image, 'https://acme.example/jane.jpg');
|
|
103
|
+
assert.equal(out.url, 'https://jane.example');
|
|
104
|
+
assert.equal(out.urlText, '@janedoe');
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
{
|
|
109
|
+
name: 'an explicit caller signoff still wins over config',
|
|
110
|
+
|
|
111
|
+
run() {
|
|
112
|
+
const out = resolveSignoff({ type: 'personal', name: 'Sam Smith, CTO' }, brandWithPerson);
|
|
113
|
+
|
|
114
|
+
assert.equal(out.name, 'Sam Smith, CTO');
|
|
115
|
+
// Unspecified fields still come from config.
|
|
116
|
+
assert.equal(out.url, 'https://jane.example');
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
{
|
|
121
|
+
name: 'firstName is derived from the brand OWN configured name',
|
|
122
|
+
|
|
123
|
+
run() {
|
|
124
|
+
assert.equal(resolvePerson(brandWithPerson).firstName, 'Jane');
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
{
|
|
129
|
+
name: 'an explicit firstName wins over the derivation',
|
|
130
|
+
|
|
131
|
+
run() {
|
|
132
|
+
const brand = { contact: { person: { name: 'Jonathan Doe, CEO', firstName: 'Jon' } } };
|
|
133
|
+
|
|
134
|
+
assert.equal(resolvePerson(brand).firstName, 'Jon');
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
{
|
|
139
|
+
name: 'optional person fields are omitted, not substituted',
|
|
140
|
+
|
|
141
|
+
run() {
|
|
142
|
+
const brand = { contact: { person: { name: 'Jane Doe' } } };
|
|
143
|
+
const out = resolveSignoff({ type: 'personal' }, brand);
|
|
144
|
+
|
|
145
|
+
assert.equal(out.image, null, 'a missing headshot must be null, not a stand-in face');
|
|
146
|
+
assert.equal(out.url, null);
|
|
147
|
+
assert.equal(out.urlText, null);
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
// ---------- Personal signoff: loud failure ----------
|
|
152
|
+
|
|
153
|
+
{
|
|
154
|
+
name: 'personal signoff with NO configured person throws',
|
|
155
|
+
|
|
156
|
+
run() {
|
|
157
|
+
assert.throws(
|
|
158
|
+
() => resolveSignoff({ type: 'personal' }, brandWithoutPerson),
|
|
159
|
+
(error) => error.code === 400 && /brand\.contact\.person\.name/.test(error.message),
|
|
160
|
+
'a missing person must fail loudly',
|
|
161
|
+
);
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
{
|
|
166
|
+
name: 'personal signoff with no brand at all throws',
|
|
167
|
+
|
|
168
|
+
run() {
|
|
169
|
+
assert.throws(() => resolveSignoff({ type: 'personal' }, undefined), (error) => error.code === 400);
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
{
|
|
174
|
+
name: 'the loud failure never leaks the framework identity',
|
|
175
|
+
|
|
176
|
+
run() {
|
|
177
|
+
// The whole point: refuse, rather than sign the mail as someone else.
|
|
178
|
+
let thrown;
|
|
179
|
+
try {
|
|
180
|
+
resolveSignoff({ type: 'personal' }, brandWithoutPerson);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
thrown = error;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
assert.ok(thrown, 'expected a throw');
|
|
186
|
+
assert.ok(!FRAMEWORK_IDENTITY.test(thrown.message), `error message leaked an identity: ${thrown.message}`);
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
{
|
|
191
|
+
name: 'a team signoff needs no person config (unchanged default path)',
|
|
192
|
+
|
|
193
|
+
run() {
|
|
194
|
+
const out = resolveSignoff({}, brandWithoutPerson);
|
|
195
|
+
|
|
196
|
+
assert.equal(out.type, 'team');
|
|
197
|
+
assert.equal(out.name, undefined);
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
// ---------- Footer: company identity ----------
|
|
202
|
+
|
|
203
|
+
{
|
|
204
|
+
name: 'footer renders the configured company name + wordmark',
|
|
205
|
+
|
|
206
|
+
run() {
|
|
207
|
+
const out = footer(brandWithPerson, {});
|
|
208
|
+
|
|
209
|
+
assert.ok(out.includes('Acme Holdings Inc'), `company name missing: ${out}`);
|
|
210
|
+
assert.ok(out.includes('https://acme.example/holdings-wordmark.png'), 'company wordmark missing');
|
|
211
|
+
assert.ok(!FRAMEWORK_IDENTITY.test(out), 'footer leaked the framework identity');
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
{
|
|
216
|
+
name: 'footer falls back to brand.name for the company name (documented schema chain)',
|
|
217
|
+
|
|
218
|
+
run() {
|
|
219
|
+
const out = footer({ name: 'Acme', url: 'https://acme.example' }, {});
|
|
220
|
+
|
|
221
|
+
assert.ok(out.includes('©') && out.includes('Acme'), `copyright name missing: ${out}`);
|
|
222
|
+
assert.ok(!FRAMEWORK_IDENTITY.test(out), 'footer leaked the framework identity');
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
{
|
|
227
|
+
name: 'footer omits the wordmark entirely when unconfigured',
|
|
228
|
+
|
|
229
|
+
run() {
|
|
230
|
+
const out = footer({ name: 'Acme', url: 'https://acme.example' }, {});
|
|
231
|
+
|
|
232
|
+
assert.ok(!out.includes('<mj-image'), `rendered a wordmark with nothing configured: ${out}`);
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
// ---------- Feedback template: no third-party asset host ----------
|
|
237
|
+
|
|
238
|
+
{
|
|
239
|
+
name: 'feedback template fetches no image from the framework CDN',
|
|
240
|
+
|
|
241
|
+
run() {
|
|
242
|
+
const out = feedbackTemplate.build({
|
|
243
|
+
data: { brand: brandWithPerson, email: { subject: 'Hi' } },
|
|
244
|
+
theme: {},
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
assert.ok(!FRAMEWORK_IDENTITY.test(out), 'feedback template leaked the framework identity');
|
|
248
|
+
assert.ok(!/<img/.test(out), `feedback template still loads a hosted image: ${out}`);
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
{
|
|
253
|
+
name: 'feedback template still renders all four rating faces',
|
|
254
|
+
|
|
255
|
+
run() {
|
|
256
|
+
const out = feedbackTemplate.build({
|
|
257
|
+
data: { brand: brandWithPerson, email: { subject: 'Hi' } },
|
|
258
|
+
theme: {},
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// The glyphs that replaced the hosted PNGs — dislike/neutral/like/love.
|
|
262
|
+
for (const face of ['😞', '😐', '🙂', '😍']) {
|
|
263
|
+
assert.ok(out.includes(face), `missing rating face ${face}`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for (const rating of ['dislike', 'neutral', 'like', 'love']) {
|
|
267
|
+
assert.ok(out.includes(`rating=${rating}`), `missing rating link for ${rating}`);
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
// ---------- Integration: audit BCCs come from config, through the real build ----------
|
|
273
|
+
|
|
274
|
+
{
|
|
275
|
+
name: 'built email: audit BCCs come from brand.contact.carbonCopy',
|
|
276
|
+
|
|
277
|
+
async run() {
|
|
278
|
+
const configured = await buildConfigured();
|
|
279
|
+
const emails = configured.bcc.map((entry) => entry.email);
|
|
280
|
+
|
|
281
|
+
assert.deepEqual(emails, ['audit@acme.example', 'archive@acme.example']);
|
|
282
|
+
assert.equal(configured.bcc[0].name, 'Acme Audit');
|
|
283
|
+
// A nameless entry falls back to the company name, not a framework one.
|
|
284
|
+
assert.equal(configured.bcc[1].name, 'Acme Holdings Inc');
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
{
|
|
289
|
+
name: 'built email: no carbonCopy config means NO bcc — never the framework addresses',
|
|
290
|
+
|
|
291
|
+
async run() {
|
|
292
|
+
const unconfigured = await buildUnconfigured();
|
|
293
|
+
|
|
294
|
+
assert.deepEqual(unconfigured.bcc, [], `unexpected bcc: ${JSON.stringify(unconfigured.bcc)}`);
|
|
295
|
+
assert.ok(!FRAMEWORK_IDENTITY.test(JSON.stringify(unconfigured)), 'built email leaked the framework identity');
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
{
|
|
300
|
+
name: 'built email: copy: true still carbon-copies the brand itself (unchanged)',
|
|
301
|
+
|
|
302
|
+
async run() {
|
|
303
|
+
const unconfigured = await buildUnconfigured();
|
|
304
|
+
|
|
305
|
+
assert.equal(unconfigured.cc[0].email, 'support@acme.example');
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
{
|
|
310
|
+
name: 'built email: a carbonCopy entry with no email fails loudly',
|
|
311
|
+
|
|
312
|
+
async run() {
|
|
313
|
+
const malformed = await buildMalformed();
|
|
314
|
+
|
|
315
|
+
assert.ok(malformed instanceof Error, 'expected a throw');
|
|
316
|
+
assert.equal(malformed.code, 400);
|
|
317
|
+
assert.ok(/carbonCopy/.test(malformed.message), `unhelpful message: ${malformed.message}`);
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
});
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consent gate test — verifies Marketing.add()/sync() skip users whose
|
|
3
|
+
* consent.marketing.status is the literal string 'revoked' (and ONLY then).
|
|
4
|
+
*
|
|
5
|
+
* Plain-node control-flow test (no emulator, no providers, no network):
|
|
6
|
+
* - isMarketingRevoked() — the pure gate semantic (revoked-only skip).
|
|
7
|
+
* - sync() — gate fires after doc resolution, BEFORE validation/providers, so a
|
|
8
|
+
* revoked doc returns { blocked: 'consent', email } with zero I/O. Proceed cases
|
|
9
|
+
* stop at the testing-mode provider guard (ctx.isTesting() → true here).
|
|
10
|
+
* - add() — by-email lookup runs through a minimal in-memory firestore stand-in to
|
|
11
|
+
* exercise add()'s wiring (block on revoked, proceed on no-user, fail open on
|
|
12
|
+
* lookup error). The emulator suites (test/routes/marketing/*) remain the
|
|
13
|
+
* integration surface for the real Firestore paths.
|
|
14
|
+
*/
|
|
15
|
+
const assert = require('node:assert');
|
|
16
|
+
const Marketing = require('../../../dist/manager/libraries/email/marketing/index.js');
|
|
17
|
+
const defineCases = require('../../../dist/vendor/devkit/test/define-cases.js');
|
|
18
|
+
|
|
19
|
+
const { isMarketingRevoked } = Marketing;
|
|
20
|
+
|
|
21
|
+
// Proceed cases must stop at the testing-mode provider guard — never let an ambient
|
|
22
|
+
// TEST_EXTENDED_MODE (or provider API keys) in the shell turn this into a live call.
|
|
23
|
+
delete process.env.TEST_EXTENDED_MODE;
|
|
24
|
+
|
|
25
|
+
// ─── isMarketingRevoked(): ONLY the literal 'revoked' blocks ───
|
|
26
|
+
const GATE_CASES = [
|
|
27
|
+
{ name: 'status revoked', doc: { consent: { marketing: { status: 'revoked' } } }, expect: true },
|
|
28
|
+
{ name: 'status granted', doc: { consent: { marketing: { status: 'granted' } } }, expect: false },
|
|
29
|
+
{ name: 'status null', doc: { consent: { marketing: { status: null } } }, expect: false },
|
|
30
|
+
{ name: 'status missing', doc: { consent: { marketing: {} } }, expect: false },
|
|
31
|
+
{ name: 'marketing missing', doc: { consent: {} }, expect: false },
|
|
32
|
+
{ name: 'consent missing (legacy user)', doc: { auth: { email: 'legacy@gmail.com' } }, expect: false },
|
|
33
|
+
{ name: 'empty doc', doc: {}, expect: false },
|
|
34
|
+
{ name: 'null doc (no user)', doc: null, expect: false },
|
|
35
|
+
{ name: 'undefined doc', doc: undefined, expect: false },
|
|
36
|
+
{ name: 'status REVOKED (case-sensitive literal)', doc: { consent: { marketing: { status: 'REVOKED' } } }, expect: false },
|
|
37
|
+
{ name: 'status pending (future enum value)', doc: { consent: { marketing: { status: 'pending' } } }, expect: false },
|
|
38
|
+
{ name: 'status true (non-string)', doc: { consent: { marketing: { status: true } } }, expect: false },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Minimal ctx — just what the Marketing constructor + gate paths read.
|
|
43
|
+
* isTesting() → true so proceed cases stop at the provider guard (no network).
|
|
44
|
+
*/
|
|
45
|
+
function buildAssistant(admin) {
|
|
46
|
+
const calls = { logs: [], warns: [], errors: [] };
|
|
47
|
+
|
|
48
|
+
const ctx = {
|
|
49
|
+
Manager: {
|
|
50
|
+
libraries: { admin },
|
|
51
|
+
config: {},
|
|
52
|
+
},
|
|
53
|
+
isTesting: () => true,
|
|
54
|
+
log: (...args) => calls.logs.push(args),
|
|
55
|
+
warn: (...args) => calls.warns.push(args),
|
|
56
|
+
error: (...args) => calls.errors.push(args),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return { ctx, calls };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Minimal in-memory firestore stand-in for add()'s by-email lookup and sync()'s
|
|
64
|
+
* by-uid fetch. `userDoc: null` → empty query result / nonexistent doc.
|
|
65
|
+
* `failLookup: true` → the query get() rejects (exercises the fail-open path).
|
|
66
|
+
*/
|
|
67
|
+
function buildAdmin({ userDoc = null, failLookup = false } = {}) {
|
|
68
|
+
const captured = { queries: [], docPaths: [] };
|
|
69
|
+
|
|
70
|
+
const admin = {
|
|
71
|
+
firestore: () => ({
|
|
72
|
+
collection: (name) => ({
|
|
73
|
+
where: (field, op, value) => {
|
|
74
|
+
captured.queries.push({ collection: name, field, op, value });
|
|
75
|
+
return {
|
|
76
|
+
limit: () => ({
|
|
77
|
+
get: async () => {
|
|
78
|
+
if (failLookup) {
|
|
79
|
+
throw new Error('firestore unavailable');
|
|
80
|
+
}
|
|
81
|
+
return userDoc
|
|
82
|
+
? { empty: false, docs: [{ id: 'test-uid', data: () => userDoc }] }
|
|
83
|
+
: { empty: true, docs: [] };
|
|
84
|
+
},
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
}),
|
|
89
|
+
doc: (path) => {
|
|
90
|
+
captured.docPaths.push(path);
|
|
91
|
+
return {
|
|
92
|
+
get: async () => ({
|
|
93
|
+
exists: !!userDoc,
|
|
94
|
+
data: () => userDoc,
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return { admin, captured };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const REVOKED_DOC = {
|
|
105
|
+
auth: { email: 'revoked.user@gmail.com' },
|
|
106
|
+
consent: { marketing: { status: 'revoked' } },
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const GRANTED_DOC = {
|
|
110
|
+
auth: { email: 'granted.user@gmail.com' },
|
|
111
|
+
consent: { marketing: { status: 'granted' } },
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const LEGACY_DOC = {
|
|
115
|
+
auth: { email: 'legacy.user@gmail.com' },
|
|
116
|
+
// No consent field at all — pre-consent-system user, must keep syncing
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
module.exports = defineCases({
|
|
120
|
+
description: 'Marketing consent gate (revoked-only skip on add/sync)',
|
|
121
|
+
type: 'group',
|
|
122
|
+
tests: [
|
|
123
|
+
// ─── 1. isMarketingRevoked() semantics ───
|
|
124
|
+
...GATE_CASES.map(({ name, doc, expect }) => ({
|
|
125
|
+
name: `isMarketingRevoked: ${name}`,
|
|
126
|
+
|
|
127
|
+
run() {
|
|
128
|
+
const actual = isMarketingRevoked(doc);
|
|
129
|
+
|
|
130
|
+
assert.strictEqual(actual, expect, `Expected ${expect}, got ${actual}`);
|
|
131
|
+
},
|
|
132
|
+
})),
|
|
133
|
+
|
|
134
|
+
// ─── 2. sync() blocks a revoked doc (gate fires before validation/providers) ───
|
|
135
|
+
{
|
|
136
|
+
name: 'sync(): blocks revoked doc',
|
|
137
|
+
|
|
138
|
+
async run() {
|
|
139
|
+
const { ctx, calls } = buildAssistant(null);
|
|
140
|
+
const result = await new Marketing(ctx).sync(REVOKED_DOC);
|
|
141
|
+
|
|
142
|
+
assert.strictEqual(result.blocked, 'consent', `Expected blocked='consent', got ${JSON.stringify(result)}`);
|
|
143
|
+
assert.strictEqual(result.email, 'revoked.user@gmail.com', `blocked result must include the email, got ${JSON.stringify(result)}`);
|
|
144
|
+
assert.strictEqual(calls.warns.length, 1, `revoked skip must log a warn, got ${calls.warns.length}`);
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
// ─── 3. sync() proceeds on missing consent (legacy user) ───
|
|
149
|
+
{
|
|
150
|
+
name: 'sync(): proceeds on missing consent',
|
|
151
|
+
|
|
152
|
+
async run() {
|
|
153
|
+
const { ctx } = buildAssistant(null);
|
|
154
|
+
const result = await new Marketing(ctx).sync(LEGACY_DOC);
|
|
155
|
+
|
|
156
|
+
assert.strictEqual(result.blocked, undefined, `Expected no block, got ${JSON.stringify(result)}`);
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// ─── 4. sync() proceeds on granted consent ───
|
|
161
|
+
{
|
|
162
|
+
name: 'sync(): proceeds on granted consent',
|
|
163
|
+
|
|
164
|
+
async run() {
|
|
165
|
+
const { ctx } = buildAssistant(null);
|
|
166
|
+
const result = await new Marketing(ctx).sync(GRANTED_DOC);
|
|
167
|
+
|
|
168
|
+
assert.strictEqual(result.blocked, undefined, `Expected no block, got ${JSON.stringify(result)}`);
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
// ─── 5. sync() by uid blocks when the fetched doc is revoked ───
|
|
173
|
+
{
|
|
174
|
+
name: 'sync(uid): blocks revoked fetched doc',
|
|
175
|
+
|
|
176
|
+
async run() {
|
|
177
|
+
const { admin, captured } = buildAdmin({ userDoc: REVOKED_DOC });
|
|
178
|
+
const { ctx } = buildAssistant(admin);
|
|
179
|
+
const result = await new Marketing(ctx).sync('revoked-uid');
|
|
180
|
+
|
|
181
|
+
assert.strictEqual(result.blocked, 'consent', `Expected blocked='consent', got ${JSON.stringify(result)}`);
|
|
182
|
+
assert.strictEqual(captured.docPaths[0], 'users/revoked-uid', `Expected a users/{uid} fetch, got ${JSON.stringify(captured.docPaths)}`);
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// ─── 6. add() blocks when the email maps to a revoked user ───
|
|
187
|
+
{
|
|
188
|
+
name: 'add(): blocks revoked user by email',
|
|
189
|
+
|
|
190
|
+
async run() {
|
|
191
|
+
const { admin, captured } = buildAdmin({ userDoc: REVOKED_DOC });
|
|
192
|
+
const { ctx, calls } = buildAssistant(admin);
|
|
193
|
+
const result = await new Marketing(ctx).add({ email: 'revoked.user@gmail.com' });
|
|
194
|
+
|
|
195
|
+
assert.strictEqual(result.blocked, 'consent', `Expected blocked='consent', got ${JSON.stringify(result)}`);
|
|
196
|
+
assert.strictEqual(result.email, 'revoked.user@gmail.com', `blocked result must include the email, got ${JSON.stringify(result)}`);
|
|
197
|
+
assert.strictEqual(calls.warns.length, 1, `revoked skip must log a warn, got ${calls.warns.length}`);
|
|
198
|
+
|
|
199
|
+
const query = captured.queries[0];
|
|
200
|
+
|
|
201
|
+
assert.ok(
|
|
202
|
+
query
|
|
203
|
+
&& query.collection === 'users'
|
|
204
|
+
&& query.field === 'auth.email'
|
|
205
|
+
&& query.op === '=='
|
|
206
|
+
&& query.value === 'revoked.user@gmail.com',
|
|
207
|
+
`add() must look up users by auth.email (the webhook-provider query), got ${JSON.stringify(query)}`,
|
|
208
|
+
);
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
// ─── 7. add() normalizes the email for the lookup ───
|
|
213
|
+
{
|
|
214
|
+
name: 'add(): lookup trims + lowercases the email',
|
|
215
|
+
|
|
216
|
+
async run() {
|
|
217
|
+
const { admin, captured } = buildAdmin({ userDoc: null });
|
|
218
|
+
const { ctx } = buildAssistant(admin);
|
|
219
|
+
await new Marketing(ctx).add({ email: ' Revoked.User@GMAIL.com ' });
|
|
220
|
+
|
|
221
|
+
assert.strictEqual(captured.queries[0]?.value, 'revoked.user@gmail.com', `Got ${JSON.stringify(captured.queries[0])}`);
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
// ─── 8. add() proceeds when no user doc exists (pure newsletter contact) ───
|
|
226
|
+
{
|
|
227
|
+
name: 'add(): proceeds when no user doc exists',
|
|
228
|
+
|
|
229
|
+
async run() {
|
|
230
|
+
const { admin } = buildAdmin({ userDoc: null });
|
|
231
|
+
const { ctx } = buildAssistant(admin);
|
|
232
|
+
const result = await new Marketing(ctx).add({ email: 'newsletter.reader@gmail.com' });
|
|
233
|
+
|
|
234
|
+
assert.strictEqual(result.blocked, undefined, `Expected no block, got ${JSON.stringify(result)}`);
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
// ─── 9. add() proceeds when the matched user has no consent field (legacy) ───
|
|
239
|
+
{
|
|
240
|
+
name: 'add(): proceeds on legacy user (no consent field)',
|
|
241
|
+
|
|
242
|
+
async run() {
|
|
243
|
+
const { admin } = buildAdmin({ userDoc: LEGACY_DOC });
|
|
244
|
+
const { ctx } = buildAssistant(admin);
|
|
245
|
+
const result = await new Marketing(ctx).add({ email: 'legacy.user@gmail.com' });
|
|
246
|
+
|
|
247
|
+
assert.strictEqual(result.blocked, undefined, `Expected no block, got ${JSON.stringify(result)}`);
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
// ─── 10. add() fails open when the lookup errors ───
|
|
252
|
+
{
|
|
253
|
+
name: 'add(): fails open on lookup error',
|
|
254
|
+
|
|
255
|
+
async run() {
|
|
256
|
+
const { admin } = buildAdmin({ failLookup: true });
|
|
257
|
+
const { ctx, calls } = buildAssistant(admin);
|
|
258
|
+
const result = await new Marketing(ctx).add({ email: 'someone@gmail.com' });
|
|
259
|
+
|
|
260
|
+
assert.strictEqual(result.blocked, undefined, `Expected no block, got ${JSON.stringify(result)}`);
|
|
261
|
+
assert.strictEqual(calls.errors.length, 1, `lookup error must be logged, got ${calls.errors.length}`);
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
});
|