@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,550 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: the test intent provider applies a validated discount to the amounts
|
|
3
|
+
*
|
|
4
|
+
* The route validates the code and records it, and the Stripe provider hands it
|
|
5
|
+
* to Stripe as a coupon — Stripe then does the math on its own checkout page. The
|
|
6
|
+
* test provider has no such page, so a discounted checkout moved no number a
|
|
7
|
+
* human could see: the confirmation URL still quoted the full price
|
|
8
|
+
* ([#239](https://github.com/Omega-JS-Stack/omega/issues/239)).
|
|
9
|
+
*
|
|
10
|
+
* Each case calls the handler DIRECTLY through the shared route harness, as its
|
|
11
|
+
* OWN seeded persona (`intent-discount-<case>`, declared in the seed roster —
|
|
12
|
+
* #406): every case buys a subscription, so one account per case is what keeps
|
|
13
|
+
* the checkout guard from rejecting the next one. Everything
|
|
14
|
+
* downstream — the provider, the auto-fired webhook, the webhook route, the
|
|
15
|
+
* on-write trigger — is the real pipeline.
|
|
16
|
+
*
|
|
17
|
+
* Product-agnostic: resolves the first paid product from config.payment.products.
|
|
18
|
+
*
|
|
19
|
+
* Run: npx omega test framework:routes/payments/intent-discount-amounts
|
|
20
|
+
*/
|
|
21
|
+
const { buildUser, callHandler } = require('./_route-harness.js');
|
|
22
|
+
const discountCodes = require('../../../dist/manager/libraries/payment/discount-codes.js');
|
|
23
|
+
const analytics = require('../../../dist/manager/events/firestore/payments-webhooks/analytics.js');
|
|
24
|
+
|
|
25
|
+
const PayPal = require('../../../dist/manager/libraries/payment/providers/paypal.js');
|
|
26
|
+
|
|
27
|
+
const handler = require('../../../dist/manager/routes/payments/intent/post.js');
|
|
28
|
+
const defineCases = require('../../../dist/vendor/devkit/test/define-cases.js');
|
|
29
|
+
|
|
30
|
+
// What each code is worth, pinned against the discount-codes SSOT below so a
|
|
31
|
+
// repriced code fails here instead of silently changing what the test asserts.
|
|
32
|
+
// Stripe coupons come in two shapes and the seeded set now carries both: a
|
|
33
|
+
// percent_off code and an amount_off one
|
|
34
|
+
// ([#239](https://github.com/Omega-JS-Stack/omega/issues/239)).
|
|
35
|
+
const PERCENT_CODE = 'WELCOME15';
|
|
36
|
+
const ONE_TIME_CODE = 'FLASH20';
|
|
37
|
+
const AMOUNT_CODE = 'WELCOME10OFF';
|
|
38
|
+
const AMOUNT_OFF = 10;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* This suite's purchaser for one case, from the seed roster
|
|
42
|
+
* ([#406](https://github.com/Omega-JS-Stack/omega/issues/406)). Every case here
|
|
43
|
+
* BUYS a subscription and the checkout guard rejects a caller who already holds
|
|
44
|
+
* one, so each case drives its own account — declared up front as
|
|
45
|
+
* `intent-discount-<case>`, never minted mid-test. The caller is built from the
|
|
46
|
+
* seeded DOC, so it is the record the route reads, not a shape invented here.
|
|
47
|
+
*/
|
|
48
|
+
async function purchaser(accounts, firestore, Manager, name) {
|
|
49
|
+
const account = accounts[`intent-discount-${name}`];
|
|
50
|
+
|
|
51
|
+
if (!account) {
|
|
52
|
+
throw new Error(`No seeded persona for the intent-discount case '${name}'`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const doc = await firestore.get(`users/${account.uid}`);
|
|
56
|
+
|
|
57
|
+
if (!doc) {
|
|
58
|
+
throw new Error(`The seeded persona for '${name}' has no user doc — the checkout guard would refuse it`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { uid: account.uid, user: buildUser(Manager, doc) };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* What schemas/payments/intent/post.js resolves a bare checkout request to — the
|
|
66
|
+
* handler receives settings already defaulted
|
|
67
|
+
*/
|
|
68
|
+
function checkoutSettings(overrides) {
|
|
69
|
+
return {
|
|
70
|
+
provider: 'test',
|
|
71
|
+
frequency: null,
|
|
72
|
+
trial: false,
|
|
73
|
+
verification: {},
|
|
74
|
+
attribution: {},
|
|
75
|
+
trackingConsent: null,
|
|
76
|
+
discount: null,
|
|
77
|
+
supplemental: {},
|
|
78
|
+
simulate: null,
|
|
79
|
+
...overrides,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function amountFromUrl(url) {
|
|
84
|
+
return new URL(url).searchParams.get('amount');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The webhook doc the test provider's auto-fired event lands in
|
|
89
|
+
*/
|
|
90
|
+
async function waitForWebhook(waitFor, firestore, eventId) {
|
|
91
|
+
return waitFor(async () => {
|
|
92
|
+
const doc = await firestore.get(`payments-webhooks/${eventId}`);
|
|
93
|
+
return doc || null;
|
|
94
|
+
}, 30000, 500);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function eventIdFor(sessionId) {
|
|
98
|
+
return sessionId.replace('_test-cs-', '_test-evt-');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = defineCases({
|
|
102
|
+
description: 'Test intent provider: discounts move the first-charge amounts',
|
|
103
|
+
type: 'group',
|
|
104
|
+
timeout: 90000,
|
|
105
|
+
|
|
106
|
+
tests: [
|
|
107
|
+
{
|
|
108
|
+
name: 'setup',
|
|
109
|
+
async run({ assert, config, state, skip }) {
|
|
110
|
+
const paidProduct = (config.payment?.products || []).find((p) => p.id !== 'basic' && p.type === 'subscription' && p.prices);
|
|
111
|
+
|
|
112
|
+
if (!paidProduct) {
|
|
113
|
+
skip('No paid subscription product configured in this brand');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
state.product = paidProduct;
|
|
117
|
+
state.frequency = Object.keys(paidProduct.prices)[0];
|
|
118
|
+
state.price = paidProduct.prices[state.frequency];
|
|
119
|
+
state.oneTimeProduct = (config.payment?.products || []).find((p) => p.type === 'one-time' && p.prices?.once);
|
|
120
|
+
|
|
121
|
+
// The other end of the same code: a frequency it covers WHOLE, which is
|
|
122
|
+
// the checkout PayPal and Coinbase cannot be handed at all (#786)
|
|
123
|
+
state.fullCoverFrequency = Object.keys(paidProduct.prices).find((f) => paidProduct.prices[f] > 0 && paidProduct.prices[f] <= AMOUNT_OFF) || null;
|
|
124
|
+
state.fullCoverPrice = state.fullCoverFrequency ? paidProduct.prices[state.fullCoverFrequency] : null;
|
|
125
|
+
|
|
126
|
+
// A flat-dollar code only MOVES a number on a charge bigger than it is —
|
|
127
|
+
// on anything smaller it floors at $0, which is also what a trial quotes.
|
|
128
|
+
// Bill the amount cases against a frequency that can show the difference.
|
|
129
|
+
state.amountFrequency = Object.keys(paidProduct.prices).find((f) => paidProduct.prices[f] > AMOUNT_OFF) || null;
|
|
130
|
+
state.amountPrice = state.amountFrequency ? paidProduct.prices[state.amountFrequency] : null;
|
|
131
|
+
|
|
132
|
+
// The codes this suite spends, straight from the SSOT
|
|
133
|
+
assert.equal(discountCodes.DISCOUNT_CODES[PERCENT_CODE].percent, 15, `${PERCENT_CODE} should be 15% off`);
|
|
134
|
+
assert.equal(discountCodes.DISCOUNT_CODES[ONE_TIME_CODE].percent, 20, `${ONE_TIME_CODE} should be 20% off`);
|
|
135
|
+
assert.equal(discountCodes.DISCOUNT_CODES[AMOUNT_CODE].amount, AMOUNT_OFF, `${AMOUNT_CODE} should be $${AMOUNT_OFF} off`);
|
|
136
|
+
assert.equal(discountCodes.DISCOUNT_CODES[AMOUNT_CODE].percent, undefined, `${AMOUNT_CODE} should be amount-based, not percent-based`);
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
{
|
|
141
|
+
name: 'a-percent-discount-lands-in-the-confirmation-url',
|
|
142
|
+
async run({ accounts, assert, firestore, Manager, state }) {
|
|
143
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'percent-url');
|
|
144
|
+
const expected = parseFloat((state.price * 0.85).toFixed(2));
|
|
145
|
+
|
|
146
|
+
const sent = await callHandler({
|
|
147
|
+
Manager,
|
|
148
|
+
handler,
|
|
149
|
+
functionName: 'payments-intent',
|
|
150
|
+
user,
|
|
151
|
+
settings: checkoutSettings({ productId: state.product.id, frequency: state.frequency, discount: PERCENT_CODE }),
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
assert.equal(sent.code, 200, `Checkout should succeed, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
155
|
+
assert.equal(amountFromUrl(sent.body.url), String(expected), `The confirmation URL should quote the discounted first charge ($${expected}), not the full $${state.price}`);
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
{
|
|
160
|
+
name: 'the-route-discounts-the-url-for-every-provider',
|
|
161
|
+
async run({ assert, state }) {
|
|
162
|
+
// WHERE this happens is the whole point. A real provider applies its
|
|
163
|
+
// coupon on its own hosted page and never revisits this URL, so doing the
|
|
164
|
+
// math provider-side left a discounted Stripe checkout landing on the
|
|
165
|
+
// confirmation page quoting the LIST price — and the client's tracking
|
|
166
|
+
// modules read that param straight into GA4/pixel revenue. Calling the
|
|
167
|
+
// route's own builder with provider=stripe is what proves the discount
|
|
168
|
+
// is the ROUTE's promise and not the test provider's.
|
|
169
|
+
const args = {
|
|
170
|
+
product: state.product,
|
|
171
|
+
productId: state.product.id,
|
|
172
|
+
productType: 'subscription',
|
|
173
|
+
frequency: state.frequency,
|
|
174
|
+
provider: 'stripe',
|
|
175
|
+
trial: false,
|
|
176
|
+
orderId: '0000-0000-0000',
|
|
177
|
+
};
|
|
178
|
+
const discount = discountCodes.validate(PERCENT_CODE);
|
|
179
|
+
const expected = parseFloat((state.price * 0.85).toFixed(2));
|
|
180
|
+
|
|
181
|
+
assert.equal(typeof handler.buildConfirmationUrl, 'function', 'The route should expose its URL builder for testing');
|
|
182
|
+
|
|
183
|
+
const discounted = handler.buildConfirmationUrl('https://example.com', { ...args, discount });
|
|
184
|
+
assert.equal(amountFromUrl(discounted), String(expected), `A Stripe checkout should quote the discounted first charge ($${expected}) too`);
|
|
185
|
+
|
|
186
|
+
const undiscounted = handler.buildConfirmationUrl('https://example.com', { ...args, discount: null });
|
|
187
|
+
assert.equal(amountFromUrl(undiscounted), String(state.price), 'An undiscounted checkout should be left at the list price');
|
|
188
|
+
|
|
189
|
+
if (state.product.trial?.days) {
|
|
190
|
+
const trialing = handler.buildConfirmationUrl('https://example.com', { ...args, trial: true, discount });
|
|
191
|
+
assert.equal(amountFromUrl(trialing), '0', 'A trial charges nothing today, coupon or not');
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
{
|
|
197
|
+
name: 'a-percent-discount-lands-on-the-webhook-subscription',
|
|
198
|
+
async run({ accounts, assert, firestore, Manager, state, waitFor }) {
|
|
199
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'percent-payload');
|
|
200
|
+
|
|
201
|
+
const sent = await callHandler({
|
|
202
|
+
Manager,
|
|
203
|
+
handler,
|
|
204
|
+
functionName: 'payments-intent',
|
|
205
|
+
user,
|
|
206
|
+
settings: checkoutSettings({ productId: state.product.id, frequency: state.frequency, discount: PERCENT_CODE }),
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
assert.equal(sent.code, 200, `Checkout should succeed, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
210
|
+
|
|
211
|
+
// Stripe attaches the coupon it applied to the subscription — the synthetic
|
|
212
|
+
// payload carries the same thing, so a reader of the webhook can see WHICH
|
|
213
|
+
// code moved the money
|
|
214
|
+
const webhookDoc = await waitForWebhook(waitFor, firestore, eventIdFor(sent.body.id));
|
|
215
|
+
const coupon = webhookDoc.raw?.data?.object?.discount?.coupon;
|
|
216
|
+
|
|
217
|
+
assert.ok(coupon, `The fired subscription should carry the discount, got ${JSON.stringify(webhookDoc.raw?.data?.object?.discount)}`);
|
|
218
|
+
assert.equal(coupon.percent_off, 15, 'The coupon should be 15% off');
|
|
219
|
+
assert.equal(coupon.duration, 'once', 'The coupon should apply to the first charge only');
|
|
220
|
+
assert.equal(coupon.name, PERCENT_CODE, 'The coupon should name the code that was redeemed');
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
{
|
|
225
|
+
name: 'a-declined-first-invoice-bills-the-discounted-amount',
|
|
226
|
+
async run({ accounts, assert, firestore, Manager, state, waitFor }) {
|
|
227
|
+
// The subscription event carries the coupon; the INVOICE is where Stripe
|
|
228
|
+
// reports the money — and the declined checkout is the one path that fires
|
|
229
|
+
// one, so it is where the discounted first charge is provable end to end
|
|
230
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'percent-invoice');
|
|
231
|
+
const expectedCents = Math.round(parseFloat((state.price * 0.85).toFixed(2)) * 100);
|
|
232
|
+
|
|
233
|
+
const sent = await callHandler({
|
|
234
|
+
Manager,
|
|
235
|
+
handler,
|
|
236
|
+
functionName: 'payments-intent',
|
|
237
|
+
user,
|
|
238
|
+
settings: checkoutSettings({ productId: state.product.id, frequency: state.frequency, discount: PERCENT_CODE, simulate: 'decline' }),
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
assert.equal(sent.code, 200, `A declined checkout still starts, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
242
|
+
|
|
243
|
+
const invoiceDoc = await waitForWebhook(waitFor, firestore, `${eventIdFor(sent.body.id)}-invoice`);
|
|
244
|
+
|
|
245
|
+
assert.equal(invoiceDoc.raw?.data?.object?.amount_due, expectedCents, `The failed first invoice should bill the discounted ${expectedCents} cents, not the full ${Math.round(state.price * 100)}`);
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
{
|
|
250
|
+
name: 'a-one-time-purchase-is-discounted-in-the-url-and-the-session',
|
|
251
|
+
async run({ accounts, assert, firestore, Manager, state, waitFor, skip }) {
|
|
252
|
+
if (!state.oneTimeProduct) {
|
|
253
|
+
skip('No one-time product configured in this brand');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'one-time');
|
|
257
|
+
const price = state.oneTimeProduct.prices.once;
|
|
258
|
+
const expected = parseFloat((price * 0.8).toFixed(2));
|
|
259
|
+
|
|
260
|
+
const sent = await callHandler({
|
|
261
|
+
Manager,
|
|
262
|
+
handler,
|
|
263
|
+
functionName: 'payments-intent',
|
|
264
|
+
user,
|
|
265
|
+
// A cadence the caller had no business sending on a one-time product —
|
|
266
|
+
// the shape the live checkout really sent
|
|
267
|
+
// ([#668](https://github.com/Omega-JS-Stack/omega/issues/668)). The
|
|
268
|
+
// route is what decides a one-time buy bills on `once`.
|
|
269
|
+
settings: checkoutSettings({ productId: state.oneTimeProduct.id, frequency: 'annually', discount: ONE_TIME_CODE }),
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
assert.equal(sent.code, 200, `Checkout should succeed, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
273
|
+
assert.equal(amountFromUrl(sent.body.url), String(expected), `The confirmation URL should quote $${expected}, not the full $${price}`);
|
|
274
|
+
|
|
275
|
+
// What the caller asked for never reaches the record: the intent doc is
|
|
276
|
+
// what the webhook and every reader after it read back (#668)
|
|
277
|
+
const intentDoc = await firestore.get(`payments-intents/${sent.body.orderId}`);
|
|
278
|
+
|
|
279
|
+
assert.equal(intentDoc.frequency, 'once', `A one-time intent should record 'once', got '${intentDoc.frequency}'`);
|
|
280
|
+
assert.equal(new URL(sent.body.url).searchParams.get('frequency'), 'once', 'And the confirmation URL should say the same');
|
|
281
|
+
assert.equal(new URL(sent.body.url).searchParams.get('type'), 'one-time', 'The confirmation URL should name the product type outright');
|
|
282
|
+
|
|
283
|
+
const webhookDoc = await waitForWebhook(waitFor, firestore, eventIdFor(sent.body.id));
|
|
284
|
+
const session = webhookDoc.raw?.data?.object;
|
|
285
|
+
|
|
286
|
+
assert.equal(session?.amount_total, Math.round(expected * 100), `The session should charge ${Math.round(expected * 100)} cents`);
|
|
287
|
+
assert.equal(session?.total_details?.amount_discount, Math.round((price - expected) * 100), 'The session should report what the coupon took off');
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
{
|
|
292
|
+
name: 'no-discount-leaves-the-amounts-alone',
|
|
293
|
+
async run({ accounts, assert, firestore, Manager, state, waitFor }) {
|
|
294
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'none');
|
|
295
|
+
|
|
296
|
+
const sent = await callHandler({
|
|
297
|
+
Manager,
|
|
298
|
+
handler,
|
|
299
|
+
functionName: 'payments-intent',
|
|
300
|
+
user,
|
|
301
|
+
settings: checkoutSettings({ productId: state.product.id, frequency: state.frequency }),
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
assert.equal(sent.code, 200, `Checkout should succeed, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
305
|
+
assert.equal(amountFromUrl(sent.body.url), String(state.price), 'An undiscounted checkout should still quote the full price');
|
|
306
|
+
|
|
307
|
+
const webhookDoc = await waitForWebhook(waitFor, firestore, eventIdFor(sent.body.id));
|
|
308
|
+
|
|
309
|
+
assert.equal(webhookDoc.raw?.data?.object?.discount, undefined, 'An undiscounted subscription should carry no coupon');
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
|
|
313
|
+
{
|
|
314
|
+
name: 'a-trial-with-a-discount-still-charges-nothing-now',
|
|
315
|
+
async run({ accounts, assert, firestore, Manager, state, skip }) {
|
|
316
|
+
if (!state.product.trial?.days) {
|
|
317
|
+
skip('The paid product configures no trial');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'trial');
|
|
321
|
+
|
|
322
|
+
const sent = await callHandler({
|
|
323
|
+
Manager,
|
|
324
|
+
handler,
|
|
325
|
+
functionName: 'payments-intent',
|
|
326
|
+
user,
|
|
327
|
+
settings: checkoutSettings({ productId: state.product.id, frequency: state.frequency, trial: true, discount: PERCENT_CODE }),
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
assert.equal(sent.code, 200, `Checkout should succeed, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
331
|
+
assert.equal(amountFromUrl(sent.body.url), '0', 'A trial charges nothing today — a coupon takes its cut off nothing');
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
{
|
|
336
|
+
name: 'an-amount-discount-lands-in-the-confirmation-url',
|
|
337
|
+
async run({ accounts, assert, firestore, Manager, state, skip }) {
|
|
338
|
+
if (!state.amountFrequency) {
|
|
339
|
+
skip(`No configured price is bigger than the $${AMOUNT_OFF} code`);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'amount-url');
|
|
343
|
+
const expected = parseFloat((state.amountPrice - AMOUNT_OFF).toFixed(2));
|
|
344
|
+
|
|
345
|
+
const sent = await callHandler({
|
|
346
|
+
Manager,
|
|
347
|
+
handler,
|
|
348
|
+
functionName: 'payments-intent',
|
|
349
|
+
user,
|
|
350
|
+
settings: checkoutSettings({ productId: state.product.id, frequency: state.amountFrequency, discount: AMOUNT_CODE }),
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
assert.equal(sent.code, 200, `Checkout should succeed, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
354
|
+
assert.equal(amountFromUrl(sent.body.url), String(expected), `The confirmation URL should quote the discounted first charge ($${expected}), not the full $${state.amountPrice}`);
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
{
|
|
359
|
+
name: 'an-amount-discount-lands-on-the-webhook-subscription-in-cents',
|
|
360
|
+
async run({ accounts, assert, firestore, Manager, state, waitFor, skip }) {
|
|
361
|
+
if (!state.amountFrequency) {
|
|
362
|
+
skip(`No configured price is bigger than the $${AMOUNT_OFF} code`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'amount-payload');
|
|
366
|
+
|
|
367
|
+
const sent = await callHandler({
|
|
368
|
+
Manager,
|
|
369
|
+
handler,
|
|
370
|
+
functionName: 'payments-intent',
|
|
371
|
+
user,
|
|
372
|
+
settings: checkoutSettings({ productId: state.product.id, frequency: state.amountFrequency, discount: AMOUNT_CODE }),
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
assert.equal(sent.code, 200, `Checkout should succeed, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
376
|
+
|
|
377
|
+
// Stripe's `amount_off` is CENTS while ours is dollars — the synthetic
|
|
378
|
+
// payload has to convert, or a reader of the webhook sees a $10 coupon
|
|
379
|
+
// as 10 cents
|
|
380
|
+
const webhookDoc = await waitForWebhook(waitFor, firestore, eventIdFor(sent.body.id));
|
|
381
|
+
const coupon = webhookDoc.raw?.data?.object?.discount?.coupon;
|
|
382
|
+
|
|
383
|
+
assert.ok(coupon, `The fired subscription should carry the discount, got ${JSON.stringify(webhookDoc.raw?.data?.object?.discount)}`);
|
|
384
|
+
assert.equal(coupon.amount_off, AMOUNT_OFF * 100, `The coupon should be ${AMOUNT_OFF * 100} cents off`);
|
|
385
|
+
assert.equal(coupon.percent_off, null, 'An amount-based coupon carries no percent');
|
|
386
|
+
assert.equal(coupon.duration, 'once', 'The coupon should apply to the first charge only');
|
|
387
|
+
assert.equal(coupon.name, AMOUNT_CODE, 'The coupon should name the code that was redeemed');
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
{
|
|
392
|
+
name: 'a-trial-with-an-amount-discount-still-charges-nothing-now',
|
|
393
|
+
async run({ accounts, assert, firestore, Manager, state, skip }) {
|
|
394
|
+
if (!state.product.trial?.days) {
|
|
395
|
+
skip('The paid product configures no trial');
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'amount-trial');
|
|
399
|
+
|
|
400
|
+
const sent = await callHandler({
|
|
401
|
+
Manager,
|
|
402
|
+
handler,
|
|
403
|
+
functionName: 'payments-intent',
|
|
404
|
+
user,
|
|
405
|
+
settings: checkoutSettings({ productId: state.product.id, frequency: state.amountFrequency || state.frequency, trial: true, discount: AMOUNT_CODE }),
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
assert.equal(sent.code, 200, `Checkout should succeed, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
409
|
+
assert.equal(amountFromUrl(sent.body.url), '0', 'A trial charges nothing today — a flat-dollar coupon comes off nothing');
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
{
|
|
414
|
+
name: 'analytics-reports-the-amount-discount-and-a-full-price-renewal',
|
|
415
|
+
async run({ assert, state, skip }) {
|
|
416
|
+
if (!state.amountFrequency) {
|
|
417
|
+
skip(`No configured price is bigger than the $${AMOUNT_OFF} code`);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Revenue is reported off the same first-charge math the URL quotes. The
|
|
421
|
+
// gate in front of it read `discount.percent > 0`, so an amount-based
|
|
422
|
+
// code would have tracked the LIST price as revenue while the customer
|
|
423
|
+
// paid less.
|
|
424
|
+
const unified = {
|
|
425
|
+
product: { id: state.product.id, name: state.product.name },
|
|
426
|
+
status: 'active',
|
|
427
|
+
trial: { claimed: false },
|
|
428
|
+
payment: { frequency: state.amountFrequency, price: state.amountPrice, resourceId: 'sub_test_analytics_amount' },
|
|
429
|
+
};
|
|
430
|
+
const order = { discount: discountCodes.validate(AMOUNT_CODE) };
|
|
431
|
+
const expected = parseFloat((state.amountPrice - AMOUNT_OFF).toFixed(2));
|
|
432
|
+
|
|
433
|
+
const resolved = analytics.resolvePaymentEvent('subscription', 'new-subscription', 'customer.subscription.created', unified, order);
|
|
434
|
+
assert.equal(resolved.value, expected, `Tracked revenue should be the discounted $${expected}, not the list $${state.amountPrice}`);
|
|
435
|
+
|
|
436
|
+
// A renewal is deliberately full price — a 'once' coupon is spent
|
|
437
|
+
const renewal = analytics.resolvePaymentEvent('subscription', null, 'invoice.payment_succeeded', unified, order);
|
|
438
|
+
assert.equal(renewal.value, state.amountPrice, 'Renewals still track the full price');
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
{
|
|
443
|
+
name: 'analytics-reports-the-discounted-amount-as-revenue',
|
|
444
|
+
async run({ assert, state }) {
|
|
445
|
+
// The same first-charge math the URL quotes is what analytics reports as
|
|
446
|
+
// revenue, and both now come from applyToAmount(). The existing analytics
|
|
447
|
+
// suite only covers full-price events, so the discounted branch is pinned
|
|
448
|
+
// here — a divergence between the two would mean the confirmation page and
|
|
449
|
+
// the server-side purchase event disagree about what the customer paid.
|
|
450
|
+
const unified = {
|
|
451
|
+
product: { id: state.product.id, name: state.product.name },
|
|
452
|
+
status: 'active',
|
|
453
|
+
trial: { claimed: false },
|
|
454
|
+
payment: { frequency: state.frequency, price: state.price, resourceId: 'sub_test_analytics_discount' },
|
|
455
|
+
};
|
|
456
|
+
const order = { discount: discountCodes.validate(PERCENT_CODE) };
|
|
457
|
+
const expected = parseFloat((state.price * 0.85).toFixed(2));
|
|
458
|
+
|
|
459
|
+
const resolved = analytics.resolvePaymentEvent('subscription', 'new-subscription', 'customer.subscription.created', unified, order);
|
|
460
|
+
|
|
461
|
+
assert.equal(resolved.reason, 'first-purchase', 'A discounted first checkout is still a first purchase');
|
|
462
|
+
assert.equal(resolved.value, expected, `Tracked revenue should be the discounted $${expected}, not the list $${state.price}`);
|
|
463
|
+
|
|
464
|
+
// A renewal is deliberately full price — a 'once' coupon is spent
|
|
465
|
+
const renewal = analytics.resolvePaymentEvent('subscription', null, 'invoice.payment_succeeded', unified, order);
|
|
466
|
+
assert.equal(renewal.value, state.price, 'Renewals still track the full price');
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
|
|
470
|
+
{
|
|
471
|
+
name: 'validate-returns-the-amount-a-flat-dollar-code-is-worth',
|
|
472
|
+
async run({ assert }) {
|
|
473
|
+
// Everything downstream reads a validate() RESULT, never the raw table —
|
|
474
|
+
// a validated amount code that reported no amount would have quietly
|
|
475
|
+
// charged full price everywhere.
|
|
476
|
+
const result = discountCodes.validate(AMOUNT_CODE.toLowerCase());
|
|
477
|
+
|
|
478
|
+
assert.equal(result.valid, true, 'The seeded amount code should validate');
|
|
479
|
+
assert.equal(result.code, AMOUNT_CODE, 'It should normalize to the uppercase code');
|
|
480
|
+
assert.equal(result.amount, AMOUNT_OFF, `It should report $${AMOUNT_OFF} off`);
|
|
481
|
+
assert.equal(result.duration, 'once', 'It should apply to the first charge only');
|
|
482
|
+
assert.equal(result.percent, undefined, 'It should carry no percent');
|
|
483
|
+
|
|
484
|
+
// A percent code is unchanged — it reports a percent and no amount
|
|
485
|
+
const percent = discountCodes.validate(PERCENT_CODE);
|
|
486
|
+
assert.equal(percent.percent, 15, 'The percent code still reports its percent');
|
|
487
|
+
assert.equal(percent.amount, undefined, 'The percent code carries no amount');
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
|
|
491
|
+
{
|
|
492
|
+
name: 'a-code-that-covers-the-whole-price-answers-400-and-never-calls-paypal',
|
|
493
|
+
async run({ accounts, assert, firestore, Manager, state, skip }) {
|
|
494
|
+
if (!state.fullCoverFrequency) {
|
|
495
|
+
skip(`No configured price is small enough for the $${AMOUNT_OFF} code to cover whole`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// The WIRE half of #786: the refusal is thrown by `chargeableAmount()`
|
|
499
|
+
// in libraries/payment/discount-codes.js and coded 400, and this route
|
|
500
|
+
// is what turns that into the buyer's answer — the one provider-path
|
|
501
|
+
// error it repeats instead of hiding behind its neutral 500 sentence.
|
|
502
|
+
// Everything else about this checkout is real; only PayPal's HTTP door
|
|
503
|
+
// is watched, and it must never open.
|
|
504
|
+
const { user } = await purchaser(accounts, firestore, Manager, 'zero-total');
|
|
505
|
+
const calls = [];
|
|
506
|
+
const realRequest = PayPal.request;
|
|
507
|
+
|
|
508
|
+
PayPal.request = async (endpoint) => {
|
|
509
|
+
calls.push(endpoint);
|
|
510
|
+
throw new Error(`PayPal was called at ${endpoint} for a $0.00 checkout`);
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
let sent;
|
|
514
|
+
|
|
515
|
+
try {
|
|
516
|
+
sent = await callHandler({
|
|
517
|
+
Manager,
|
|
518
|
+
handler,
|
|
519
|
+
functionName: 'payments-intent',
|
|
520
|
+
user,
|
|
521
|
+
settings: checkoutSettings({ provider: 'paypal', productId: state.product.id, frequency: state.fullCoverFrequency, discount: AMOUNT_CODE }),
|
|
522
|
+
});
|
|
523
|
+
} finally {
|
|
524
|
+
PayPal.request = realRequest;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
assert.equal(sent.code, 400, `A fully covered price is the buyer's own 400, got ${sent.code}: ${JSON.stringify(sent.body)}`);
|
|
528
|
+
assert.match(String(sent.body), new RegExp(AMOUNT_CODE), 'The answer names the code they entered');
|
|
529
|
+
assert.match(String(sent.body), new RegExp(`\\$${state.fullCoverPrice.toFixed(2)}`), `And the $${state.fullCoverPrice} price it covered`);
|
|
530
|
+
assert.match(String(sent.body), /PayPal/, 'And the payment method that cannot take it');
|
|
531
|
+
assert.ok(!/could not start your checkout/i.test(String(sent.body)), 'Never the neutral sentence a real provider fault gets');
|
|
532
|
+
assert.equal(calls.length, 0, `PayPal was never called, got ${JSON.stringify(calls)}`);
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
|
|
536
|
+
{
|
|
537
|
+
name: 'an-amount-discount-comes-off-the-first-charge',
|
|
538
|
+
async run({ assert }) {
|
|
539
|
+
// Stripe coupons come in both shapes (percent_off, amount_off), so the math
|
|
540
|
+
// the test provider runs handles both — pinned here on the pure function
|
|
541
|
+
// across the edges the seeded codes do not reach.
|
|
542
|
+
assert.equal(discountCodes.applyToAmount(99.99, { valid: true, code: 'X', amount: 15, duration: 'once' }), 84.99, '$15 off $99.99 should be $84.99');
|
|
543
|
+
assert.equal(discountCodes.applyToAmount(99.99, { valid: true, code: 'X', percent: 15, duration: 'once' }), 84.99, '15% off $99.99 should be $84.99');
|
|
544
|
+
assert.equal(discountCodes.applyToAmount(9.99, { valid: true, code: 'X', amount: 50, duration: 'once' }), 0, 'A discount bigger than the charge should floor at $0, never go negative');
|
|
545
|
+
assert.equal(discountCodes.applyToAmount(9.99, null), 9.99, 'No discount should leave the charge alone');
|
|
546
|
+
assert.equal(discountCodes.applyToAmount(0, { valid: true, code: 'X', percent: 15 }), 0, 'A $0 charge stays $0');
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
});
|