@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,597 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: POST /payments/winback — the cancel-flow save offer's apply path
|
|
3
|
+
* ([#268](https://github.com/Omega-JS-Stack/omega/issues/268)).
|
|
4
|
+
*
|
|
5
|
+
* The offer is pitched before the cancellation questionnaire and accepting it
|
|
6
|
+
* discounts the next cycle instead of ending the subscription. What that offer
|
|
7
|
+
* IS belongs to the brand (`payment.winback`, resolved by @omega.js/config with a
|
|
8
|
+
* 50%-off default), so this suite reads the brand's own resolution rather than
|
|
9
|
+
* asserting a number.
|
|
10
|
+
*
|
|
11
|
+
* Two layers, the same split cancel.test.js and plan.test.js use:
|
|
12
|
+
* - the wire guards and the happy path over `http.as(...)`, which is what
|
|
13
|
+
* proves the route is registered, auth-gated and schema-validated at all;
|
|
14
|
+
* - the per-subscription guards and the provider capability gate through
|
|
15
|
+
* DIRECT handler calls (the _route-harness technique), so one test can choose
|
|
16
|
+
* a provider and a subscription shape without minting a persona each.
|
|
17
|
+
*
|
|
18
|
+
* The offer is claimed ONCE: the claim lives on
|
|
19
|
+
* payments-orders/{orderId}.requests.winback, so the second call is refused
|
|
20
|
+
* against the same document the first one wrote.
|
|
21
|
+
*
|
|
22
|
+
* EVERY refusal carries a branchable code on `omega-properties`
|
|
23
|
+
* ([#311](https://github.com/Omega-JS-Stack/omega/issues/311)): the client
|
|
24
|
+
* pitches the offer off the account alone, so any refusal it cannot name leaves
|
|
25
|
+
* the customer in a dialog arming a retry that can never succeed. Each guard
|
|
26
|
+
* below asserts its own code for that reason.
|
|
27
|
+
*
|
|
28
|
+
* Run: npx omega test framework:routes/payments/winback
|
|
29
|
+
*/
|
|
30
|
+
const { buildUser, recordingResponse } = require('./_route-harness.js');
|
|
31
|
+
const winback = require('../../../dist/manager/libraries/payment/winback.js');
|
|
32
|
+
|
|
33
|
+
const handler = require('../../../dist/manager/routes/payments/winback/post.js');
|
|
34
|
+
const defineCases = require('../../../dist/vendor/devkit/test/define-cases.js');
|
|
35
|
+
|
|
36
|
+
function providerModule(name) {
|
|
37
|
+
return require(`../../../dist/manager/routes/payments/winback/providers/${name}.js`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const YEAR = 365 * 24 * 60 * 60;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A paying subscriber the offer can be made to.
|
|
44
|
+
*
|
|
45
|
+
* @param {object} Manager - The @omega.js/backend Manager
|
|
46
|
+
* @param {object} options - uid, product, provider, resourceId, and the state overrides
|
|
47
|
+
*/
|
|
48
|
+
function subscriber(Manager, { uid, product, provider, resourceId, orderId, pending, trial, status }) {
|
|
49
|
+
const lastYearUNIX = Math.floor(Date.now() / 1000) - YEAR;
|
|
50
|
+
const nextMonthUNIX = Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60);
|
|
51
|
+
|
|
52
|
+
return buildUser(Manager, {
|
|
53
|
+
auth: { uid: uid, email: `${uid}@example.com` },
|
|
54
|
+
roles: {},
|
|
55
|
+
subscription: {
|
|
56
|
+
product: { id: product.id, name: product.name || product.id },
|
|
57
|
+
status: status === undefined ? 'active' : status,
|
|
58
|
+
cancellation: { pending: pending === true },
|
|
59
|
+
expires: trial
|
|
60
|
+
? { timestamp: new Date(nextMonthUNIX * 1000).toISOString(), timestampUNIX: nextMonthUNIX }
|
|
61
|
+
: { timestamp: new Date(nextMonthUNIX * 1000).toISOString(), timestampUNIX: nextMonthUNIX },
|
|
62
|
+
...(trial
|
|
63
|
+
? { trial: { claimed: true, expires: { timestamp: new Date(nextMonthUNIX * 1000).toISOString(), timestampUNIX: nextMonthUNIX } } }
|
|
64
|
+
: {}),
|
|
65
|
+
payment: {
|
|
66
|
+
provider: provider === undefined ? 'test' : provider,
|
|
67
|
+
resourceId: resourceId === undefined ? 'sub_test_winback_guard' : resourceId,
|
|
68
|
+
orderId: orderId === undefined ? null : orderId,
|
|
69
|
+
frequency: 'monthly',
|
|
70
|
+
startDate: { timestamp: new Date(lastYearUNIX * 1000).toISOString(), timestampUNIX: lastYearUNIX },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A direct call with the `omega-properties` header captured — the
|
|
78
|
+
* branchable half of a 4xx rides that header, so a test asserting a CODE reads
|
|
79
|
+
* it (plan.test.js's technique, for the same gate).
|
|
80
|
+
*
|
|
81
|
+
* @returns {Promise<{ sent: object, properties: object|null }>}
|
|
82
|
+
*/
|
|
83
|
+
async function acceptOfferReadingProperties(Manager, user, settings) {
|
|
84
|
+
const res = recordingResponse();
|
|
85
|
+
const headers = {};
|
|
86
|
+
|
|
87
|
+
res.header = (key, value) => {
|
|
88
|
+
headers[key] = value;
|
|
89
|
+
return res;
|
|
90
|
+
};
|
|
91
|
+
res.get = (key) => headers[key];
|
|
92
|
+
|
|
93
|
+
const req = { method: 'POST', headers: { 'content-type': 'application/json' }, query: {}, body: {} };
|
|
94
|
+
const ctx = Manager.RouteContext({ req, res }, { functionName: 'payments-winback' });
|
|
95
|
+
|
|
96
|
+
// The REAL analytics library, attached the way the middleware attaches it —
|
|
97
|
+
// every refusal returns before the route's accept event, but the success path
|
|
98
|
+
// records one, and a ctx built without it would fail on a line the wire never
|
|
99
|
+
// reaches this way. Not a stand-in: in a test environment the library itself
|
|
100
|
+
// skips the send.
|
|
101
|
+
ctx.analytics = Manager.Analytics({ ctx: ctx, uuid: user.auth.uid });
|
|
102
|
+
|
|
103
|
+
await handler({ ctx, Manager, user, settings: { confirmed: true, ...(settings || {}) }, libraries: Manager.libraries });
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
sent: res.sent,
|
|
107
|
+
properties: headers['omega-properties'] ? JSON.parse(headers['omega-properties']) : null,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Run the thunk with the brand's save offer replaced, restoring it after. */
|
|
112
|
+
async function withOffer(Manager, winbackConfig, fn) {
|
|
113
|
+
const payment = Manager.config.payment;
|
|
114
|
+
const original = payment.winback;
|
|
115
|
+
|
|
116
|
+
if (winbackConfig === null) delete payment.winback;
|
|
117
|
+
else payment.winback = winbackConfig;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
return await fn();
|
|
121
|
+
} finally {
|
|
122
|
+
if (original === undefined) delete payment.winback;
|
|
123
|
+
else payment.winback = original;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// The paid subscription product the offer is made against.
|
|
128
|
+
function paidProduct(config, skip) {
|
|
129
|
+
const paid = (config.payment?.products || []).find((p) => p.id !== 'basic' && p.type === 'subscription' && p.prices?.monthly);
|
|
130
|
+
|
|
131
|
+
if (!paid) {
|
|
132
|
+
skip('No paid subscription product with a monthly price configured in this brand');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return paid;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
module.exports = defineCases({
|
|
139
|
+
description: 'Payment winback endpoint: the save offer apply path',
|
|
140
|
+
type: 'group',
|
|
141
|
+
timeout: 30000,
|
|
142
|
+
|
|
143
|
+
tests: [
|
|
144
|
+
// ─── the wire guards ───
|
|
145
|
+
|
|
146
|
+
{
|
|
147
|
+
name: 'rejects-unauthenticated',
|
|
148
|
+
async run({ http, assert }) {
|
|
149
|
+
const response = await http.as('none').post('backend-manager/payments/winback', {
|
|
150
|
+
confirmed: true,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
assert.isError(response, 401, 'Should reject unauthenticated request');
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
{
|
|
158
|
+
name: 'rejects-missing-confirmed',
|
|
159
|
+
async run({ http, assert }) {
|
|
160
|
+
const response = await http.as('basic').post('backend-manager/payments/winback', {});
|
|
161
|
+
|
|
162
|
+
assert.isError(response, 400, 'Should reject a request that confirms nothing');
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
{
|
|
167
|
+
name: 'rejects-basic-user',
|
|
168
|
+
async run({ http, assert }) {
|
|
169
|
+
const response = await http.as('basic').post('backend-manager/payments/winback', {
|
|
170
|
+
confirmed: true,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
assert.isError(response, 400, 'Should reject a user with no paid subscription to keep');
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
// ─── the offer itself ───
|
|
178
|
+
|
|
179
|
+
{
|
|
180
|
+
name: 'resolves-the-brand-offer-with-the-framework-default',
|
|
181
|
+
async run({ Manager, assert }) {
|
|
182
|
+
// The 50% default has ONE home (@omega.js/config). A brand that
|
|
183
|
+
// configures nothing still has an offer, and it is that one.
|
|
184
|
+
await withOffer(Manager, null, async () => {
|
|
185
|
+
const offer = winback.resolveOffer(Manager.config);
|
|
186
|
+
|
|
187
|
+
assert.equal(offer.enabled, true, 'the offer is on by default');
|
|
188
|
+
assert.equal(offer.percent, 50, 'and it is 50% off');
|
|
189
|
+
assert.equal(offer.duration, 'once', 'for one cycle');
|
|
190
|
+
|
|
191
|
+
const discount = winback.toDiscount(offer);
|
|
192
|
+
|
|
193
|
+
assert.equal(discount.valid, true, 'it hands downstream a validate()-shaped discount');
|
|
194
|
+
assert.equal(discount.code, 'WINBACK50', 'named for what it is');
|
|
195
|
+
assert.equal(discount.amount, undefined, 'a percent offer declares no amount at all');
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
{
|
|
201
|
+
name: 'refuses-when-the-brand-disabled-the-offer',
|
|
202
|
+
async run({ Manager, assert, config, skip }) {
|
|
203
|
+
const product = paidProduct(config, skip);
|
|
204
|
+
|
|
205
|
+
await withOffer(Manager, { enabled: false }, async () => {
|
|
206
|
+
const user = subscriber(Manager, { uid: '_test-winback-disabled', product });
|
|
207
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
208
|
+
|
|
209
|
+
assert.equal(sent.code, 400, 'Should refuse an offer the brand turned off');
|
|
210
|
+
assert.equal(
|
|
211
|
+
properties?.additional?.code,
|
|
212
|
+
'offer-disabled',
|
|
213
|
+
'the refusal carries a code the billing card can branch on',
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
{
|
|
220
|
+
name: 'refuses-an-unconfirmed-request',
|
|
221
|
+
async run({ Manager, assert, config, skip }) {
|
|
222
|
+
const product = paidProduct(config, skip);
|
|
223
|
+
const user = subscriber(Manager, { uid: '_test-winback-unconfirmed', product });
|
|
224
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user, { confirmed: false });
|
|
225
|
+
|
|
226
|
+
assert.equal(sent.code, 400, 'Should refuse a request that confirms nothing');
|
|
227
|
+
assert.equal(
|
|
228
|
+
properties?.additional?.code,
|
|
229
|
+
'confirmation-required',
|
|
230
|
+
'and says which refusal it was — the ONE code a retry can actually fix',
|
|
231
|
+
);
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
// ─── the per-subscription guards ───
|
|
236
|
+
|
|
237
|
+
{
|
|
238
|
+
name: 'refuses-a-trial',
|
|
239
|
+
async run({ Manager, assert, config, skip }) {
|
|
240
|
+
// A trial cancel ends access immediately (#267) and nothing has been
|
|
241
|
+
// paid, so there is no next cycle to discount. The billing card gates
|
|
242
|
+
// the same way, off the same rule.
|
|
243
|
+
const product = paidProduct(config, skip);
|
|
244
|
+
const user = subscriber(Manager, { uid: '_test-winback-trial', product, trial: true });
|
|
245
|
+
|
|
246
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
247
|
+
|
|
248
|
+
assert.equal(sent.code, 400, 'Should refuse a subscription still inside its free trial');
|
|
249
|
+
assert.equal(
|
|
250
|
+
properties?.additional?.code,
|
|
251
|
+
'trial-not-eligible',
|
|
252
|
+
'the refusal carries a code the billing card can branch on',
|
|
253
|
+
);
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
{
|
|
258
|
+
name: 'refuses-a-scheduled-cancellation',
|
|
259
|
+
async run({ Manager, assert, config, skip }) {
|
|
260
|
+
const product = paidProduct(config, skip);
|
|
261
|
+
const user = subscriber(Manager, { uid: '_test-winback-pending', product, pending: true });
|
|
262
|
+
|
|
263
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
264
|
+
|
|
265
|
+
assert.equal(sent.code, 400, 'Should refuse when the cancellation is already scheduled');
|
|
266
|
+
assert.equal(
|
|
267
|
+
properties?.additional?.code,
|
|
268
|
+
'cancellation-pending',
|
|
269
|
+
'the refusal carries the same code the plan switch refuses that state with',
|
|
270
|
+
);
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
{
|
|
275
|
+
name: 'refuses-a-suspended-subscription',
|
|
276
|
+
async run({ Manager, assert, config, skip }) {
|
|
277
|
+
const product = paidProduct(config, skip);
|
|
278
|
+
const user = subscriber(Manager, { uid: '_test-winback-suspended', product, status: 'suspended' });
|
|
279
|
+
|
|
280
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
281
|
+
|
|
282
|
+
assert.equal(sent.code, 400, 'Should refuse a subscription that is not active');
|
|
283
|
+
assert.equal(
|
|
284
|
+
properties?.additional?.code,
|
|
285
|
+
'no-active-subscription',
|
|
286
|
+
'the refusal carries a code the billing card can branch on',
|
|
287
|
+
);
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
{
|
|
292
|
+
name: 'refuses-missing-payment-details',
|
|
293
|
+
async run({ Manager, assert, config, skip }) {
|
|
294
|
+
// An ADMIN-GRANTED or imported subscription is paid and active with no
|
|
295
|
+
// provider details on it at all, and the client pitches what it can
|
|
296
|
+
// read — so this refusal needs a code as much as the capability gate
|
|
297
|
+
// does ([#311]): without one, accepting shows an error toast and leaves
|
|
298
|
+
// the dialog armed for a retry that can never succeed. HALF the details
|
|
299
|
+
// is the same dead end, so each half is proven on its own.
|
|
300
|
+
const product = paidProduct(config, skip);
|
|
301
|
+
const halves = [
|
|
302
|
+
{ what: 'provider', provider: null, resourceId: 'sub_test_winback_guard' },
|
|
303
|
+
{ what: 'resourceId', provider: 'test', resourceId: null },
|
|
304
|
+
{ what: 'both', provider: null, resourceId: null },
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
for (const { what, provider, resourceId } of halves) {
|
|
308
|
+
const user = subscriber(Manager, { uid: `_test-winback-no-${what}`, product, provider, resourceId });
|
|
309
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
310
|
+
|
|
311
|
+
assert.equal(sent.code, 400, `missing ${what}: Should refuse a subscription the route cannot reach a provider with`);
|
|
312
|
+
assert.equal(
|
|
313
|
+
properties?.additional?.code,
|
|
314
|
+
'missing-payment-details',
|
|
315
|
+
`missing ${what}: the refusal carries a code the billing card can branch on`,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
{
|
|
322
|
+
name: 'refuses-an-unknown-provider',
|
|
323
|
+
async run({ Manager, assert, config, skip }) {
|
|
324
|
+
const product = paidProduct(config, skip);
|
|
325
|
+
const user = subscriber(Manager, { uid: '_test-winback-unknown', product, provider: 'not-a-provider' });
|
|
326
|
+
|
|
327
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
328
|
+
|
|
329
|
+
assert.equal(sent.code, 400, 'Should refuse a provider that does not exist');
|
|
330
|
+
assert.equal(
|
|
331
|
+
properties?.additional?.code,
|
|
332
|
+
'unknown-provider',
|
|
333
|
+
'the refusal carries a code the billing card can branch on',
|
|
334
|
+
);
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
{
|
|
339
|
+
name: 'refuses-when-the-claim-has-nowhere-to-be-recorded',
|
|
340
|
+
async run({ Manager, assert, config, skip }) {
|
|
341
|
+
// "Claimed once" is only true while there is a document to record the
|
|
342
|
+
// claim on. A subscription carrying no orderId (dashboard-created,
|
|
343
|
+
// imported, a metadata backfill that never landed) has none, so the
|
|
344
|
+
// offer is refused BEFORE dispatch rather than becoming takeable on
|
|
345
|
+
// every cancel dialog — each accept re-couponing the subscription.
|
|
346
|
+
const product = paidProduct(config, skip);
|
|
347
|
+
const user = subscriber(Manager, { uid: '_test-winback-no-order', product });
|
|
348
|
+
const provider = providerModule('test');
|
|
349
|
+
const applied = [];
|
|
350
|
+
const realApplyOffer = provider.applyOffer;
|
|
351
|
+
|
|
352
|
+
provider.applyOffer = async (options) => applied.push(options);
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
356
|
+
|
|
357
|
+
assert.equal(sent.code, 400, 'Should refuse an offer whose claim cannot be recorded');
|
|
358
|
+
assert.equal(
|
|
359
|
+
properties?.additional?.code,
|
|
360
|
+
'offer-not-claimable',
|
|
361
|
+
'the refusal carries a code the billing card can branch on',
|
|
362
|
+
);
|
|
363
|
+
assert.equal(applied.length, 0, 'and nothing reached the provider');
|
|
364
|
+
} finally {
|
|
365
|
+
provider.applyOffer = realApplyOffer;
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
{
|
|
371
|
+
name: 'refuses-a-second-claim-with-a-branchable-code',
|
|
372
|
+
async run({ Manager, assert, config, firestore, skip }) {
|
|
373
|
+
// The offer is claimed ONCE, and a past claimant who opens the cancel
|
|
374
|
+
// dialog again is pitched it anyway — the client reads the account, not
|
|
375
|
+
// the order doc. So the refusal carries a code the billing card can
|
|
376
|
+
// branch on ([#310]): without one, accepting shows an error toast and
|
|
377
|
+
// leaves the dialog armed for a retry that can never succeed.
|
|
378
|
+
const product = paidProduct(config, skip);
|
|
379
|
+
const orderId = '_test-winback-claimed-order';
|
|
380
|
+
const user = subscriber(Manager, { uid: '_test-winback-claimed', product, orderId });
|
|
381
|
+
const provider = providerModule('test');
|
|
382
|
+
const applied = [];
|
|
383
|
+
const realApplyOffer = provider.applyOffer;
|
|
384
|
+
|
|
385
|
+
// The first claim, written where the route records it
|
|
386
|
+
await firestore.set(`payments-orders/${orderId}`, {
|
|
387
|
+
requests: {
|
|
388
|
+
winback: {
|
|
389
|
+
discount: winback.toDiscount(winback.resolveOffer(Manager.config)),
|
|
390
|
+
date: { timestamp: new Date().toISOString(), timestampUNIX: Math.floor(Date.now() / 1000) },
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
}, { merge: true });
|
|
394
|
+
|
|
395
|
+
provider.applyOffer = async (options) => applied.push(options);
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
399
|
+
|
|
400
|
+
assert.equal(sent.code, 400, 'Should refuse an offer this subscription already took');
|
|
401
|
+
assert.equal(
|
|
402
|
+
properties?.additional?.code,
|
|
403
|
+
'offer-already-claimed',
|
|
404
|
+
'the refusal carries a code the billing card can branch on',
|
|
405
|
+
);
|
|
406
|
+
assert.equal(applied.length, 0, 'and the provider is never asked to discount twice');
|
|
407
|
+
} finally {
|
|
408
|
+
provider.applyOffer = realApplyOffer;
|
|
409
|
+
await firestore.delete(`payments-orders/${orderId}`);
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
// ─── the claim on the account ───
|
|
415
|
+
|
|
416
|
+
{
|
|
417
|
+
name: 'records-the-applied-discount-on-the-account',
|
|
418
|
+
async run({ Manager, assert, config, firestore, skip }) {
|
|
419
|
+
// The order doc is the offer's MEMORY — what a second claim is refused
|
|
420
|
+
// against — but the billing card reads the ACCOUNT, and a saving that
|
|
421
|
+
// vanishes on reload was never announced at all ([#325]). So the claim
|
|
422
|
+
// lands on both, and the account's copy has to survive the SAME resolver
|
|
423
|
+
// the client reads it through (which strips every key the schema does
|
|
424
|
+
// not name).
|
|
425
|
+
const product = paidProduct(config, skip);
|
|
426
|
+
const uid = '_test-winback-account';
|
|
427
|
+
const orderId = '_test-winback-account-order';
|
|
428
|
+
const user = subscriber(Manager, { uid, product, orderId });
|
|
429
|
+
const provider = providerModule('test');
|
|
430
|
+
const realApplyOffer = provider.applyOffer;
|
|
431
|
+
const applied = [];
|
|
432
|
+
|
|
433
|
+
provider.applyOffer = async (options) => applied.push(options);
|
|
434
|
+
|
|
435
|
+
try {
|
|
436
|
+
const { sent } = await acceptOfferReadingProperties(Manager, user);
|
|
437
|
+
|
|
438
|
+
assert.equal(sent.code, 200, 'Should apply the save offer');
|
|
439
|
+
assert.equal(applied.length, 1, 'and the provider discounted the live subscription once');
|
|
440
|
+
|
|
441
|
+
const userDoc = await firestore.get(`users/${uid}`);
|
|
442
|
+
const discount = userDoc?.subscription?.discount;
|
|
443
|
+
|
|
444
|
+
assert.equal(discount?.valid, true, 'The account carries the discount that was applied');
|
|
445
|
+
assert.equal(discount.code, sent.body.discount.code, 'the same one the route answered with');
|
|
446
|
+
assert.equal(discount.duration, sent.body.discount.duration, 'for the same duration');
|
|
447
|
+
assert.equal(
|
|
448
|
+
discount.percent > 0 || discount.amount > 0,
|
|
449
|
+
true,
|
|
450
|
+
'and it is worth something — both shapes are written, so a merge can never leave half of an older discount behind',
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
// The source is the whole reason this is safe to read as a CLAIM: a
|
|
454
|
+
// checkout code sets the same node, and a winback pitch suppressed by
|
|
455
|
+
// someone else's promo is an offer silently withheld.
|
|
456
|
+
assert.equal(discount.source, 'winback', 'and it says which system applied it');
|
|
457
|
+
|
|
458
|
+
// And WHICH subscription it was applied to ([#333]). Nothing cleared
|
|
459
|
+
// this node, so a customer who churned and resubscribed carried the
|
|
460
|
+
// old claim into the new subscription and was never pitched the save
|
|
461
|
+
// again. The stamp is what the webhook pipeline compares the incoming
|
|
462
|
+
// subscription against, so the claim can end with the subscription it
|
|
463
|
+
// was made on.
|
|
464
|
+
assert.equal(
|
|
465
|
+
discount.resourceId,
|
|
466
|
+
user.subscription.payment.resourceId,
|
|
467
|
+
'stamped with the subscription it discounted',
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
// Through the resolver, exactly as the client reads it
|
|
471
|
+
const resolved = Manager.User(userDoc).properties.subscription.discount;
|
|
472
|
+
|
|
473
|
+
assert.equal(resolved.valid, true, 'The discount survives account resolution');
|
|
474
|
+
assert.equal(resolved.source, 'winback', 'source and all');
|
|
475
|
+
assert.equal(resolved.resourceId, user.subscription.payment.resourceId, 'stamp and all');
|
|
476
|
+
|
|
477
|
+
// The claim is still recorded where the refusal reads it
|
|
478
|
+
const orderDoc = await firestore.get(`payments-orders/${orderId}`);
|
|
479
|
+
assert.equal(orderDoc.requests.winback.discount.code, discount.code, 'The order doc keeps the offer memory');
|
|
480
|
+
|
|
481
|
+
// A second accept changes NOTHING: it is refused before dispatch, and
|
|
482
|
+
// the account's discount is not doubled, re-stamped or cleared.
|
|
483
|
+
const { sent: second, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
484
|
+
|
|
485
|
+
assert.equal(second.code, 400, 'Should refuse a second claim');
|
|
486
|
+
assert.equal(properties?.additional?.code, 'offer-already-claimed', 'with the branchable code');
|
|
487
|
+
assert.equal(applied.length, 1, 'the provider is never asked twice');
|
|
488
|
+
|
|
489
|
+
const after = (await firestore.get(`users/${uid}`))?.subscription?.discount;
|
|
490
|
+
|
|
491
|
+
assert.deepEqual(after, discount, 'and the account carries exactly the one discount it already had');
|
|
492
|
+
} finally {
|
|
493
|
+
provider.applyOffer = realApplyOffer;
|
|
494
|
+
await firestore.delete(`payments-orders/${orderId}`);
|
|
495
|
+
await firestore.delete(`users/${uid}`);
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
|
|
500
|
+
// ─── the provider capability gate ───
|
|
501
|
+
|
|
502
|
+
{
|
|
503
|
+
name: 'declares-which-providers-can-apply-the-offer',
|
|
504
|
+
async run({ assert }) {
|
|
505
|
+
// The export IS the declaration. Stripe rides the coupon plumbing the
|
|
506
|
+
// checkout already uses; the test provider mirrors it. PayPal has no
|
|
507
|
+
// discount object at all, and Chargebee has coupons but no way to reach
|
|
508
|
+
// a LIVE subscription with one through plumbing that exists here — both
|
|
509
|
+
// say so by exporting nothing.
|
|
510
|
+
assert.equal(typeof providerModule('stripe').applyOffer, 'function', 'Stripe applies the offer');
|
|
511
|
+
assert.equal(typeof providerModule('test').applyOffer, 'function', 'the test provider applies the offer');
|
|
512
|
+
assert.equal(typeof providerModule('paypal').applyOffer, 'undefined', 'PayPal declares it cannot');
|
|
513
|
+
assert.equal(typeof providerModule('chargebee').applyOffer, 'undefined', 'Chargebee declares it cannot');
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
|
|
517
|
+
{
|
|
518
|
+
name: 'refuses-a-provider-that-cannot-discount-with-a-branchable-code',
|
|
519
|
+
async run({ Manager, assert, config, skip }) {
|
|
520
|
+
const product = paidProduct(config, skip);
|
|
521
|
+
|
|
522
|
+
for (const provider of ['paypal', 'chargebee']) {
|
|
523
|
+
const user = subscriber(Manager, { uid: `_test-winback-${provider}`, product, provider, resourceId: `sub_${provider}_winback` });
|
|
524
|
+
const { sent, properties } = await acceptOfferReadingProperties(Manager, user);
|
|
525
|
+
|
|
526
|
+
assert.equal(sent.code, 400, `${provider}: Should refuse before dispatch`);
|
|
527
|
+
assert.equal(
|
|
528
|
+
properties?.additional?.code,
|
|
529
|
+
'not-supported-by-provider',
|
|
530
|
+
`${provider}: the refusal carries the code the billing card branches on`,
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
|
|
536
|
+
// ─── the happy path, over the wire ───
|
|
537
|
+
|
|
538
|
+
{
|
|
539
|
+
name: 'applies-the-offer-and-claims-it-once',
|
|
540
|
+
async run({ http, assert, config, accounts, firestore, waitFor, skip }) {
|
|
541
|
+
const uid = accounts['route-winback-success'].uid;
|
|
542
|
+
const product = paidProduct(config, skip);
|
|
543
|
+
|
|
544
|
+
// Step 1: a real paid subscription on the test provider
|
|
545
|
+
const intentResponse = await http.as('route-winback-success').post('backend-manager/payments/intent', {
|
|
546
|
+
provider: 'test',
|
|
547
|
+
productId: product.id,
|
|
548
|
+
frequency: 'monthly',
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
assert.isSuccess(intentResponse, 'Intent should succeed');
|
|
552
|
+
|
|
553
|
+
// Step 2: the auto-webhook activates it
|
|
554
|
+
await waitFor(async () => {
|
|
555
|
+
const userDoc = await firestore.get(`users/${uid}`);
|
|
556
|
+
return userDoc?.subscription?.payment?.provider === 'test'
|
|
557
|
+
&& userDoc?.subscription?.payment?.resourceId
|
|
558
|
+
&& userDoc?.subscription?.status === 'active';
|
|
559
|
+
}, 15000, 500);
|
|
560
|
+
|
|
561
|
+
// Step 3: the customer starts cancelling and takes the offer instead
|
|
562
|
+
const response = await http.as('route-winback-success').post('backend-manager/payments/winback', {
|
|
563
|
+
confirmed: true,
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
assert.isSuccess(response, 'Should apply the save offer');
|
|
567
|
+
assert.equal(response.data.success, true, 'Should return success: true');
|
|
568
|
+
assert.equal(response.data.discount.valid, true, 'Should answer with the discount it applied');
|
|
569
|
+
|
|
570
|
+
// Step 4: the subscription is UNCHANGED — the cancel never happened and
|
|
571
|
+
// a coupon does not move the plan, the cadence or the renewal
|
|
572
|
+
const userDoc = await firestore.get(`users/${uid}`);
|
|
573
|
+
assert.equal(userDoc.subscription.status, 'active', 'The subscription is still active');
|
|
574
|
+
assert.equal(userDoc.subscription.cancellation?.pending, false, 'and nothing is scheduled to cancel');
|
|
575
|
+
|
|
576
|
+
// Step 5: the claim is on the order doc — the offer's whole memory
|
|
577
|
+
const orderId = userDoc.subscription.payment.orderId;
|
|
578
|
+
const orderDoc = await firestore.get(`payments-orders/${orderId}`);
|
|
579
|
+
|
|
580
|
+
assert.equal(orderDoc.requests.winback.discount.code, response.data.discount.code, 'The claim records the discount applied');
|
|
581
|
+
assert.ok(orderDoc.requests.winback.date.timestampUNIX > 0, 'and when it was claimed');
|
|
582
|
+
|
|
583
|
+
// …and on the ACCOUNT, which is what the billing card reads ([#325])
|
|
584
|
+
assert.equal(userDoc.subscription.discount.code, response.data.discount.code, 'The account carries the applied discount');
|
|
585
|
+
assert.equal(userDoc.subscription.discount.source, 'winback', 'stamped with the system that applied it');
|
|
586
|
+
|
|
587
|
+
// Step 6: it is claimed ONCE — an offer takeable on every cancel dialog
|
|
588
|
+
// is a permanent discount nobody agreed to
|
|
589
|
+
const second = await http.as('route-winback-success').post('backend-manager/payments/winback', {
|
|
590
|
+
confirmed: true,
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
assert.isError(second, 400, 'Should refuse a second claim on the same subscription');
|
|
594
|
+
},
|
|
595
|
+
},
|
|
596
|
+
],
|
|
597
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: test/authenticate
|
|
3
|
+
* Tests different authentication methods using new RESTful API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const defineCases = require('../../../dist/vendor/devkit/test/define-cases.js');
|
|
7
|
+
module.exports = defineCases({
|
|
8
|
+
description: 'Authentication methods (RESTful)',
|
|
9
|
+
type: 'group',
|
|
10
|
+
tests: [
|
|
11
|
+
// Test 1: Unauthenticated request
|
|
12
|
+
{
|
|
13
|
+
name: 'no-auth',
|
|
14
|
+
auth: 'none',
|
|
15
|
+
async run({ http, assert }) {
|
|
16
|
+
const response = await http.get('backend-manager/test/authenticate');
|
|
17
|
+
|
|
18
|
+
assert.isSuccess(response, 'Should succeed without auth');
|
|
19
|
+
assert.equal(response.data.user.authenticated, false, 'User should not be authenticated');
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// Test 2: Private key authentication
|
|
24
|
+
{
|
|
25
|
+
name: 'private-key',
|
|
26
|
+
auth: 'basic',
|
|
27
|
+
async run({ http, assert, accounts }) {
|
|
28
|
+
const response = await http.as('basic').get('backend-manager/test/authenticate');
|
|
29
|
+
|
|
30
|
+
assert.isSuccess(response, 'Should succeed with privateKey');
|
|
31
|
+
assert.equal(response.data.user.authenticated, true, 'User should be authenticated');
|
|
32
|
+
assert.equal(response.data.user.auth.uid, accounts.basic.uid, 'UID should match');
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// Test 3: Invalid private key
|
|
37
|
+
{
|
|
38
|
+
name: 'invalid-private-key',
|
|
39
|
+
auth: 'none',
|
|
40
|
+
async run({ http, assert }) {
|
|
41
|
+
const response = await http.withPrivateKey('invalid-key-12345').get('backend-manager/test/authenticate');
|
|
42
|
+
|
|
43
|
+
assert.isSuccess(response, 'Should succeed but not authenticate');
|
|
44
|
+
assert.equal(response.data.user.authenticated, false, 'Invalid key should not authenticate');
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Test 4: Admin (admin key) authentication
|
|
49
|
+
{
|
|
50
|
+
name: 'admin-key-header',
|
|
51
|
+
auth: 'admin',
|
|
52
|
+
async run({ http, assert }) {
|
|
53
|
+
const response = await http.as('admin').get('backend-manager/test/authenticate');
|
|
54
|
+
|
|
55
|
+
assert.isSuccess(response, 'Should succeed with admin key');
|
|
56
|
+
assert.equal(response.data.user.authenticated, true, 'User should be authenticated');
|
|
57
|
+
assert.equal(response.data.user.roles?.admin, true, 'Should have admin role');
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// Test 5: The RETIRED wire — the real admin key as a request parameter
|
|
62
|
+
// must NOT grant admin (only the omega-admin-key header does). Query and
|
|
63
|
+
// body merge into the SAME request.data object authenticate() used to
|
|
64
|
+
// read, so the query variant kills both lanes (the route is GET-only).
|
|
65
|
+
{
|
|
66
|
+
name: 'legacy-key-field-dead',
|
|
67
|
+
auth: 'none',
|
|
68
|
+
async run({ http, assert, config }) {
|
|
69
|
+
const viaQuery = await http.as('none').get('backend-manager/test/authenticate', {
|
|
70
|
+
backendManagerKey: config.adminKey,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
assert.isSuccess(viaQuery, 'Request itself should succeed');
|
|
74
|
+
assert.equal(viaQuery.data.user.authenticated, false, 'Legacy backendManagerKey param must NOT authenticate');
|
|
75
|
+
assert.equal(viaQuery.data.user.roles?.admin ?? false, false, 'Legacy backendManagerKey param must NOT grant admin');
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
});
|