@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,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: the one-time purchase-refunded handler's record of the refund, and the
|
|
3
|
+
* mail it owes the customer
|
|
4
|
+
* ([#212](https://github.com/Omega-JS-Stack/omega/issues/212),
|
|
5
|
+
* [#673](https://github.com/Omega-JS-Stack/omega/issues/673)).
|
|
6
|
+
*
|
|
7
|
+
* The handler's log line is the operator's record: it used to name the order and
|
|
8
|
+
* nothing else, because on-write.js resolved the provider's refund details for the
|
|
9
|
+
* subscription transition only. The CUSTOMER got nothing at all — the handler was
|
|
10
|
+
* a log-only stub, so somebody refunded on a one-time purchase heard about it from
|
|
11
|
+
* their bank statement. It now sends through the same generator its subscription
|
|
12
|
+
* twin uses (`order` template, `refunded` event).
|
|
13
|
+
*
|
|
14
|
+
* The handler is called directly — the dispatch that calls it is fire-and-forget
|
|
15
|
+
* and skipped in testing mode, so the emulator journey cannot see either.
|
|
16
|
+
*
|
|
17
|
+
* The email library is RECORDED rather than run: it is an external sink (SendGrid),
|
|
18
|
+
* the same treatment the webhook harness gives the Sentry handle.
|
|
19
|
+
*
|
|
20
|
+
* Run: npx omega test backend:events/payments/purchase-refunded-handler
|
|
21
|
+
*/
|
|
22
|
+
const handler = require('../../../dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-refunded.js');
|
|
23
|
+
const defineCases = require('../../../dist/vendor/devkit/test/define-cases.js');
|
|
24
|
+
|
|
25
|
+
const ORDER_ID = '9090-8080-7070';
|
|
26
|
+
|
|
27
|
+
function context(logs, sent) {
|
|
28
|
+
return {
|
|
29
|
+
before: null,
|
|
30
|
+
after: { product: { id: 'credits-100', name: '100 Credits' }, status: 'refunded' },
|
|
31
|
+
order: { id: ORDER_ID, type: 'one-time', unified: { product: { id: 'credits-100' }, payment: { price: 9.99 } } },
|
|
32
|
+
uid: '_test-purchase-refunded-uid',
|
|
33
|
+
userDoc: { auth: { uid: '_test-purchase-refunded-uid', email: 'buyer@test.dev' } },
|
|
34
|
+
ctx: {
|
|
35
|
+
log: (line) => logs.push(line),
|
|
36
|
+
error: (line) => logs.push(line),
|
|
37
|
+
Manager: {
|
|
38
|
+
config: { brand: { name: 'Test Brand' } },
|
|
39
|
+
Email: () => ({ send: async (payload) => { sent.push(payload); return { status: 'sent' }; } }),
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
refundDetails: { amount: '9.99', currency: 'USD', reason: 'requested_by_customer' },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = defineCases({
|
|
47
|
+
description: 'One-time purchase-refunded handler',
|
|
48
|
+
type: 'group',
|
|
49
|
+
|
|
50
|
+
tests: [
|
|
51
|
+
{
|
|
52
|
+
name: 'records-the-amount-that-came-back',
|
|
53
|
+
async run({ assert }) {
|
|
54
|
+
const logs = [];
|
|
55
|
+
|
|
56
|
+
await handler(context(logs, []));
|
|
57
|
+
|
|
58
|
+
const line = logs.find((entry) => entry.includes('one-time/purchase-refunded'));
|
|
59
|
+
|
|
60
|
+
assert.ok(line, `The handler should log the transition, got: ${logs.join(' | ')}`);
|
|
61
|
+
assert.match(line, new RegExp(`orderId=${ORDER_ID}`), 'The line should name the order refunded');
|
|
62
|
+
assert.match(line, /amount=9\.99 USD/, 'The line should say how much came back');
|
|
63
|
+
assert.match(line, /reason=requested_by_customer/, 'The line should carry the provider reason');
|
|
64
|
+
assert.match(line, /product=credits-100/, 'The line should name what was refunded');
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
{
|
|
69
|
+
name: 'stays-readable-without-refund-details',
|
|
70
|
+
async run({ assert }) {
|
|
71
|
+
// A provider library with no getRefundDetails() leaves them null — the
|
|
72
|
+
// record must still say which order was refunded
|
|
73
|
+
const logs = [];
|
|
74
|
+
const ctx = context(logs, []);
|
|
75
|
+
ctx.refundDetails = null;
|
|
76
|
+
|
|
77
|
+
await handler(ctx);
|
|
78
|
+
|
|
79
|
+
const line = logs.find((entry) => entry.includes('one-time/purchase-refunded'));
|
|
80
|
+
|
|
81
|
+
assert.match(line, new RegExp(`orderId=${ORDER_ID}`), 'The line should still name the order');
|
|
82
|
+
assert.match(line, /amount=unknown USD/, 'An unresolved amount should read as unknown, never as undefined');
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
name: 'sends-the-refunded-email-the-subscription-twin-sends',
|
|
88
|
+
async run({ assert }) {
|
|
89
|
+
const sent = [];
|
|
90
|
+
|
|
91
|
+
await handler(context([], sent));
|
|
92
|
+
|
|
93
|
+
assert.equal(sent.length, 1, `A refunded purchase owes the customer exactly one email, got ${sent.length}`);
|
|
94
|
+
|
|
95
|
+
const email = sent[0];
|
|
96
|
+
|
|
97
|
+
assert.equal(email.template, 'order', 'It rides the one order template, like every other transition');
|
|
98
|
+
assert.deepEqual(email.categories, ['order/refunded'], 'Filed under the same category the subscription refund is');
|
|
99
|
+
assert.equal(email.data.content.event, 'refunded', 'The order template renders the refunded variant off this event');
|
|
100
|
+
assert.match(email.subject, new RegExp(ORDER_ID), 'The subject should name the order refunded');
|
|
101
|
+
assert.equal(email.data.content.id, ORDER_ID, 'The order rides the payload, so the receipt can quote it');
|
|
102
|
+
assert.equal(email.data.content._computed.refundAmount, '9.99', 'The refund amount is what the mail is about');
|
|
103
|
+
assert.equal(email.data.content._computed.refundCurrency, 'USD', 'And its currency');
|
|
104
|
+
assert.equal(email.data.content._computed.refundReason, 'requested_by_customer', 'The provider reason rides along, as the twin sends it');
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
});
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: every test processor writes the pipeline doc the ROUTE writes
|
|
3
|
+
*
|
|
4
|
+
* The test provider's cancel, refund, plan and uncancel processors skip the HTTP
|
|
5
|
+
* door and write `payments-webhooks/{eventId}` themselves — which makes them the
|
|
6
|
+
* only writers of that document besides the webhook route, and the only ones
|
|
7
|
+
* nothing verifies against it. The Stage 1 review found them spelling the metadata
|
|
8
|
+
* block `received`/`processed` where the route spells it `created`/`completed`
|
|
9
|
+
* ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)).
|
|
10
|
+
*
|
|
11
|
+
* `metadata.created.timestampUNIX` is not decoration: it is the pipeline's
|
|
12
|
+
* STALENESS CLOCK — the number `processPaymentEvent()` compares against the order's
|
|
13
|
+
* last write to decide an out-of-order delivery. A synthetic doc that never wrote
|
|
14
|
+
* it handed the clock nothing, and every test-processor event rode the now-fallback
|
|
15
|
+
* as if it had just arrived. Harmless while the fallback holds, and exactly the
|
|
16
|
+
* kind of drift that stops being harmless the moment the fallback changes.
|
|
17
|
+
*
|
|
18
|
+
* Plain-node (no emulator, no network): each processor is called directly against
|
|
19
|
+
* the shared in-memory Firestore stand-in, and the document it left behind is the
|
|
20
|
+
* assertion. The route's own doc is built beside them from the SAME source the
|
|
21
|
+
* route uses, so this compares two real shapes rather than one shape and a copy of
|
|
22
|
+
* itself in a fixture.
|
|
23
|
+
*
|
|
24
|
+
* Run: npx omega test backend:events/payments/test-processor-doc-shape
|
|
25
|
+
*/
|
|
26
|
+
const assert = require('node:assert');
|
|
27
|
+
const { buildAdmin, CONFIG } = require('./_webhook-harness.js');
|
|
28
|
+
|
|
29
|
+
const cancelProcessor = require('../../../dist/manager/routes/payments/cancel/providers/test.js');
|
|
30
|
+
const refundProcessor = require('../../../dist/manager/routes/payments/refund/providers/test.js');
|
|
31
|
+
const planProcessor = require('../../../dist/manager/routes/payments/plan/providers/test.js');
|
|
32
|
+
const uncancelProcessor = require('../../../dist/manager/routes/payments/uncancel/providers/test.js');
|
|
33
|
+
const defineCases = require('../../../dist/vendor/devkit/test/define-cases.js');
|
|
34
|
+
|
|
35
|
+
const UID = '_test-doc-shape-uid';
|
|
36
|
+
const RESOURCE_ID = '_test-doc-shape-sub';
|
|
37
|
+
const ORDER_ID = '_test-doc-shape-order';
|
|
38
|
+
|
|
39
|
+
const DAY = 24 * 60 * 60;
|
|
40
|
+
|
|
41
|
+
/** A `$timestamp` pair from a UNIX second */
|
|
42
|
+
function stamp(unix) {
|
|
43
|
+
return { timestamp: new Date(unix * 1000).toISOString(), timestampUNIX: unix };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The paid subscription every processor here acts on */
|
|
47
|
+
function subscription() {
|
|
48
|
+
const nowUNIX = Math.floor(Date.now() / 1000);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
product: { id: 'premium', name: 'Premium' },
|
|
52
|
+
status: 'active',
|
|
53
|
+
expires: stamp(nowUNIX + 20 * DAY),
|
|
54
|
+
trial: { claimed: false },
|
|
55
|
+
cancellation: { pending: false },
|
|
56
|
+
payment: { provider: 'test', orderId: ORDER_ID, resourceId: RESOURCE_ID, frequency: 'monthly', price: 4.99, startDate: stamp(nowUNIX - 30 * DAY) },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The purchase record behind it */
|
|
61
|
+
function order() {
|
|
62
|
+
return {
|
|
63
|
+
id: ORDER_ID,
|
|
64
|
+
type: 'subscription',
|
|
65
|
+
owner: UID,
|
|
66
|
+
productId: 'premium',
|
|
67
|
+
provider: 'test',
|
|
68
|
+
resourceId: RESOURCE_ID,
|
|
69
|
+
unified: { ...subscription(), product: { id: 'premium', name: 'Premium' } },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Run one processor against the stand-in and hand back every payments-webhooks doc
|
|
75
|
+
* it wrote
|
|
76
|
+
*
|
|
77
|
+
* @param {function} act - `(ctx) => Promise` — the processor call under test
|
|
78
|
+
* @returns {Promise<object[]>} The synthetic pipeline documents
|
|
79
|
+
*/
|
|
80
|
+
async function synthesize(act) {
|
|
81
|
+
const { admin, store } = buildAdmin({
|
|
82
|
+
seed: { [`payments-orders/${ORDER_ID}`]: order() },
|
|
83
|
+
authUids: [UID],
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const ctx = {
|
|
87
|
+
Manager: { config: CONFIG, libraries: { admin } },
|
|
88
|
+
isProduction: () => false,
|
|
89
|
+
isTesting: () => true,
|
|
90
|
+
log: () => {},
|
|
91
|
+
warn: () => {},
|
|
92
|
+
error: () => {},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
await act(ctx);
|
|
96
|
+
|
|
97
|
+
return [...store.entries()]
|
|
98
|
+
.filter(([path]) => path.startsWith('payments-webhooks/'))
|
|
99
|
+
.map(([, data]) => data);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The four processors, each reduced to the one call that writes a pipeline doc */
|
|
103
|
+
const PROCESSORS = [
|
|
104
|
+
['cancel', (ctx) => cancelProcessor.cancelAtPeriodEnd({ resourceId: RESOURCE_ID, uid: UID, subscription: subscription(), ctx })],
|
|
105
|
+
['refund', (ctx) => refundProcessor.processRefund({ resourceId: RESOURCE_ID, uid: UID, subscription: subscription(), ctx })],
|
|
106
|
+
['plan', (ctx) => planProcessor.switchPlan({ resourceId: RESOURCE_ID, uid: UID, subscription: subscription(), product: CONFIG.payment.products.find((p) => p.id === 'premium'), frequency: 'monthly', ctx })],
|
|
107
|
+
['uncancel', (ctx) => uncancelProcessor.uncancel({ resourceId: RESOURCE_ID, uid: UID, subscription: subscription(), ctx })],
|
|
108
|
+
['refund (one-time)', (ctx) => refundProcessor.processOneTimeRefund({ resourceId: RESOURCE_ID, uid: UID, order: { ...order(), type: 'one-time' }, ctx })],
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
module.exports = defineCases({
|
|
112
|
+
description: 'Test processors write the same pipeline-doc shape the webhook route does',
|
|
113
|
+
type: 'group',
|
|
114
|
+
timeout: 30000,
|
|
115
|
+
|
|
116
|
+
tests: [
|
|
117
|
+
{
|
|
118
|
+
name: 'every-processor-stamps-the-staleness-clock-the-pipeline-reads',
|
|
119
|
+
|
|
120
|
+
async run() {
|
|
121
|
+
for (const [name, act] of PROCESSORS) {
|
|
122
|
+
const docs = await synthesize(act);
|
|
123
|
+
|
|
124
|
+
assert.equal(docs.length, 1, `the ${name} processor should write exactly one pipeline doc, got ${docs.length}`);
|
|
125
|
+
|
|
126
|
+
const [doc] = docs;
|
|
127
|
+
|
|
128
|
+
assert.equal(
|
|
129
|
+
typeof doc.metadata?.created?.timestampUNIX,
|
|
130
|
+
'number',
|
|
131
|
+
`the ${name} processor must stamp metadata.created.timestampUNIX — it is the number the pipeline's staleness guard compares against the order`,
|
|
132
|
+
);
|
|
133
|
+
assert.equal(typeof doc.metadata?.created?.timestamp, 'string', `the ${name} processor must stamp metadata.created.timestamp beside it`);
|
|
134
|
+
assert.ok('completed' in (doc.metadata || {}), `the ${name} processor must open metadata.completed, the slot the pipeline closes out`);
|
|
135
|
+
assert.equal(doc.metadata.completed.timestampUNIX, null, `the ${name} processor must leave metadata.completed empty — nothing has processed yet`);
|
|
136
|
+
|
|
137
|
+
assert.equal(doc.metadata.received, undefined, `the ${name} processor must not spell the arrival stamp 'received' — the route calls it 'created' and the pipeline only reads that one`);
|
|
138
|
+
assert.equal(doc.metadata.processed, undefined, `the ${name} processor must not spell the completion stamp 'processed' — the route calls it 'completed'`);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
{
|
|
144
|
+
name: 'every-processor-writes-the-rest-of-the-envelope-the-pipeline-needs',
|
|
145
|
+
|
|
146
|
+
async run() {
|
|
147
|
+
for (const [name, act] of PROCESSORS) {
|
|
148
|
+
const [doc] = await synthesize(act);
|
|
149
|
+
|
|
150
|
+
assert.equal(doc.provider, 'test', `the ${name} processor's doc names the provider whose library the pipeline loads`);
|
|
151
|
+
assert.equal(doc.status, 'pending', `the ${name} processor's doc must be pending — the trigger short-circuits on anything else`);
|
|
152
|
+
assert.equal(doc.owner, UID, `the ${name} processor's doc carries the owner the event is about`);
|
|
153
|
+
assert.equal(doc.error, null, `the ${name} processor's doc opens with no error`);
|
|
154
|
+
assert.ok(doc.event?.type, `the ${name} processor's doc names an event type`);
|
|
155
|
+
assert.ok(doc.event?.category, `the ${name} processor's doc names a category — the pipeline throws without one`);
|
|
156
|
+
assert.ok(doc.event?.resourceId, `the ${name} processor's doc names the resource the event is about`);
|
|
157
|
+
assert.equal(doc.raw?.type, doc.event.type, `the ${name} processor's envelope and its parsed event must name the same event`);
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
});
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: every payments transition that owes the customer an email actually sends
|
|
3
|
+
* one, and it names what they bought
|
|
4
|
+
* ([#774](https://github.com/Omega-JS-Stack/omega/issues/774)).
|
|
5
|
+
*
|
|
6
|
+
* Until the mailer grew its testing-mode capture there was no way to assert this
|
|
7
|
+
* offline: the webhook pipeline gates its whole handler dispatch on
|
|
8
|
+
* `ctx.isTesting()` (`shouldRunHandlers` in on-write.js — a coarse gate that also
|
|
9
|
+
* covers payment analytics and the marketing sync, so it is NOT the email seam and
|
|
10
|
+
* stays), and the webhook suites could only count the `handler skipped (testing
|
|
11
|
+
* mode)` log line. The product name a receipt exists to state
|
|
12
|
+
* ([#668](https://github.com/Omega-JS-Stack/omega/issues/668)) was proved by
|
|
13
|
+
* nothing.
|
|
14
|
+
*
|
|
15
|
+
* So the transition is driven the way the framework already drives one in a test:
|
|
16
|
+
* the handler module is called DIRECTLY, exactly as
|
|
17
|
+
* `purchase-failed-handler.test.js` and `transition-promo-lines.test.js` do. What
|
|
18
|
+
* changes here is that the email door is NOT swapped — the REAL `Manager.Email()`
|
|
19
|
+
* runs, through the real brand, the real template data and the real MJML render,
|
|
20
|
+
* and the capture is what the assertions read.
|
|
21
|
+
*
|
|
22
|
+
* Plain-node (no emulator, no network): an order email addresses a user DOCUMENT,
|
|
23
|
+
* so the send resolves no uid against Firestore and touches nothing but the store.
|
|
24
|
+
*
|
|
25
|
+
* Run: npx omega test framework:events/payments/transition-order-emails
|
|
26
|
+
*/
|
|
27
|
+
const assert = require('node:assert');
|
|
28
|
+
const newSubscription = require('../../../dist/manager/events/firestore/payments-webhooks/transitions/subscription/new-subscription.js');
|
|
29
|
+
const purchaseCompleted = require('../../../dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-completed.js');
|
|
30
|
+
const checkoutDeclined = require('../../../dist/manager/events/firestore/payments-webhooks/transitions/subscription/checkout-declined.js');
|
|
31
|
+
const capture = require('../../../dist/test/utils/email-capture.js');
|
|
32
|
+
const defineCases = require('../../../dist/vendor/devkit/test/define-cases.js');
|
|
33
|
+
|
|
34
|
+
const UID = '_test-transition-order-emails';
|
|
35
|
+
const USER_DOC = {
|
|
36
|
+
auth: { uid: UID, email: `${UID}@test.dev` },
|
|
37
|
+
personal: { name: { first: 'Ordell' } },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The handlers dispatch their send fire-and-forget (on-write.js never awaits one),
|
|
42
|
+
* so a test waits for the record the same way the pipeline's own caller would see
|
|
43
|
+
* it land — by looking.
|
|
44
|
+
*
|
|
45
|
+
* @param {object} Manager - The booted Manager whose project owns the store
|
|
46
|
+
* @param {number} count - How many records to wait for
|
|
47
|
+
* @returns {Promise<object[]>} The records, once there are `count` of them
|
|
48
|
+
*/
|
|
49
|
+
async function waitForCaptured(Manager, count) {
|
|
50
|
+
const deadline = Date.now() + 10000;
|
|
51
|
+
|
|
52
|
+
while (Date.now() < deadline) {
|
|
53
|
+
const records = capture.readCaptured(Manager);
|
|
54
|
+
|
|
55
|
+
if (records.length >= count) {
|
|
56
|
+
return records;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
throw new Error(`Timed out waiting for ${count} captured email(s); got ${capture.readCaptured(Manager).length}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = defineCases({
|
|
66
|
+
description: 'Payment transitions send the order email their customer is owed (#774)',
|
|
67
|
+
type: 'group',
|
|
68
|
+
timeout: 30000,
|
|
69
|
+
|
|
70
|
+
tests: [
|
|
71
|
+
{
|
|
72
|
+
name: 'a-new-subscription-emails-the-receipt-that-names-the-plan',
|
|
73
|
+
|
|
74
|
+
async run({ Manager, ctx }) {
|
|
75
|
+
capture.clearCaptured(Manager);
|
|
76
|
+
|
|
77
|
+
const after = {
|
|
78
|
+
product: { id: 'premium', name: 'Premium' },
|
|
79
|
+
payment: { price: 4.99, frequency: 'monthly', provider: 'test' },
|
|
80
|
+
status: 'active',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
await newSubscription({
|
|
84
|
+
before: { product: { id: 'basic', name: 'Basic' }, status: 'active' },
|
|
85
|
+
after,
|
|
86
|
+
order: {
|
|
87
|
+
id: '_test-order-subscription',
|
|
88
|
+
type: 'subscription',
|
|
89
|
+
unified: after,
|
|
90
|
+
discount: null,
|
|
91
|
+
},
|
|
92
|
+
uid: UID,
|
|
93
|
+
userDoc: USER_DOC,
|
|
94
|
+
ctx,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const [record] = await waitForCaptured(Manager, 1);
|
|
98
|
+
const brandName = Manager.config.brand.name;
|
|
99
|
+
|
|
100
|
+
assert.deepEqual(record.to, [USER_DOC.auth.email], 'the receipt goes to the subscriber');
|
|
101
|
+
assert.equal(record.template, 'order', 'on the order template');
|
|
102
|
+
assert.match(record.subject, /Premium order #_test-order-subscription/, `the subject names the plan and the order, got: ${record.subject}`);
|
|
103
|
+
|
|
104
|
+
// The one thing a receipt exists to state (#668), and the line that tells a
|
|
105
|
+
// subscription apart from a one-time buy.
|
|
106
|
+
assert.match(record.summary, new RegExp(`${brandName} Premium`), `the summary names the product, got: ${record.summary}`);
|
|
107
|
+
assert.match(record.summary, /Billed monthly/, `and how it bills, got: ${record.summary}`);
|
|
108
|
+
assert.match(record.summary, /Total paid today \$4\.99/, `and what was charged, got: ${record.summary}`);
|
|
109
|
+
|
|
110
|
+
capture.clearCaptured(Manager);
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
{
|
|
115
|
+
name: 'a-one-time-purchase-emails-the-receipt-that-names-the-product',
|
|
116
|
+
|
|
117
|
+
async run({ Manager, ctx }) {
|
|
118
|
+
capture.clearCaptured(Manager);
|
|
119
|
+
|
|
120
|
+
const after = {
|
|
121
|
+
product: { id: 'credits-100', name: '100 Credits' },
|
|
122
|
+
payment: { price: 9.99, provider: 'test', resourceId: '_test-charge' },
|
|
123
|
+
status: 'completed',
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
await purchaseCompleted({
|
|
127
|
+
before: null,
|
|
128
|
+
after,
|
|
129
|
+
order: {
|
|
130
|
+
id: '_test-order-one-time',
|
|
131
|
+
type: 'one-time',
|
|
132
|
+
unified: after,
|
|
133
|
+
discount: null,
|
|
134
|
+
},
|
|
135
|
+
uid: UID,
|
|
136
|
+
userDoc: USER_DOC,
|
|
137
|
+
ctx,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const [record] = await waitForCaptured(Manager, 1);
|
|
141
|
+
const brandName = Manager.config.brand.name;
|
|
142
|
+
|
|
143
|
+
assert.deepEqual(record.to, [USER_DOC.auth.email], 'the receipt goes to the buyer');
|
|
144
|
+
assert.equal(record.template, 'order');
|
|
145
|
+
assert.match(record.subject, /100 Credits order #_test-order-one-time/, `the subject names the product, got: ${record.subject}`);
|
|
146
|
+
|
|
147
|
+
// The #668 shape: the row used to be labelled with the order id the header
|
|
148
|
+
// already prints, so the product appeared nowhere in the email.
|
|
149
|
+
assert.match(record.summary, new RegExp(`${brandName} 100 Credits`), `the summary names the product, got: ${record.summary}`);
|
|
150
|
+
assert.match(record.summary, /One-time purchase/, `and says it is not a subscription, got: ${record.summary}`);
|
|
151
|
+
assert.match(record.summary, /Total paid today \$9\.99/, `and what was charged, got: ${record.summary}`);
|
|
152
|
+
|
|
153
|
+
capture.clearCaptured(Manager);
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
{
|
|
158
|
+
name: 'a-transition-that-owes-no-email-sends-none',
|
|
159
|
+
|
|
160
|
+
async run({ Manager, ctx }) {
|
|
161
|
+
capture.clearCaptured(Manager);
|
|
162
|
+
|
|
163
|
+
// checkout-declined is log-only on purpose: the customer is standing at the
|
|
164
|
+
// checkout watching the decline, and the dunning copy its cousin sends is
|
|
165
|
+
// addressed to somebody mid-subscription ([#212]). An empty capture is the
|
|
166
|
+
// only thing that can prove a deliberate silence.
|
|
167
|
+
await checkoutDeclined({
|
|
168
|
+
before: { product: { id: 'basic', name: 'Basic' }, status: 'active' },
|
|
169
|
+
after: { product: { id: 'premium', name: 'Premium' }, status: 'suspended' },
|
|
170
|
+
order: { id: '_test-order-declined', type: 'subscription' },
|
|
171
|
+
uid: UID,
|
|
172
|
+
userDoc: USER_DOC,
|
|
173
|
+
ctx,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// A send is fire-and-forget, so absence needs a settle rather than a look:
|
|
177
|
+
// long enough for the render + append the sending transitions above finish
|
|
178
|
+
// inside, which waitForCaptured() measures at well under this.
|
|
179
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
180
|
+
|
|
181
|
+
assert.deepEqual(capture.readCaptured(Manager), [], 'a log-only transition emails nobody');
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
});
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: the promo line + totals the order-confirmation transitions compute
|
|
3
|
+
* ([#239](https://github.com/Omega-JS-Stack/omega/issues/239)).
|
|
4
|
+
*
|
|
5
|
+
* `new-subscription` and `purchase-completed` pre-compute `_computed` for the order
|
|
6
|
+
* email. Three shapes reach them: a percent code, a flat-amount code, and — from an
|
|
7
|
+
* order written before the amount field existed — a valid discount carrying
|
|
8
|
+
* NEITHER. The third must not render a promo line and must not throw: these
|
|
9
|
+
* handlers are dispatched fire-and-forget, so a TypeError in here silently costs
|
|
10
|
+
* the customer their confirmation email.
|
|
11
|
+
*
|
|
12
|
+
* The totals go through applyToAmount() for every shape, so `totalToday` is what
|
|
13
|
+
* was actually charged rather than the list price.
|
|
14
|
+
*
|
|
15
|
+
* Run: npx omega test framework:events/payments/transition-promo-lines
|
|
16
|
+
*
|
|
17
|
+
* The REAL transition modules run. The one thing swapped is the email door
|
|
18
|
+
* (`ctx.Manager.Email`) — sending would hit the real provider — and it is swapped
|
|
19
|
+
* on a VIEW of the Manager (`Object.create`), so the runner's own Manager is never
|
|
20
|
+
* mutated. Everything else (the discount validation, the arithmetic, the template
|
|
21
|
+
* data) is the real path.
|
|
22
|
+
*/
|
|
23
|
+
const newSubscription = require('../../../dist/manager/events/firestore/payments-webhooks/transitions/subscription/new-subscription.js');
|
|
24
|
+
const purchaseCompleted = require('../../../dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-completed.js');
|
|
25
|
+
const discountCodes = require('../../../dist/manager/libraries/payment/discount-codes.js');
|
|
26
|
+
const defineCases = require('../../../dist/vendor/devkit/test/define-cases.js');
|
|
27
|
+
|
|
28
|
+
const PRICE = 49.99;
|
|
29
|
+
const UID = '_test-transition-promo';
|
|
30
|
+
|
|
31
|
+
// What an order written before the amount field existed looks like coming back
|
|
32
|
+
// out of Firestore: valid, named, and carrying no shape either reader can use
|
|
33
|
+
const LEGACY_SHAPELESS_DISCOUNT = { valid: true, code: 'LEGACYCODE', duration: 'once' };
|
|
34
|
+
|
|
35
|
+
const USER_DOC = { auth: { uid: UID, email: `${UID}@example.com` } };
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A ctx whose Manager is the real one with ONLY the email door swapped, so the
|
|
39
|
+
* transition's own `sendOrderEmail()` path runs for real up to the send.
|
|
40
|
+
*/
|
|
41
|
+
function buildCtx(Manager, captured) {
|
|
42
|
+
const managerView = Object.create(Manager);
|
|
43
|
+
|
|
44
|
+
managerView.Email = () => ({
|
|
45
|
+
send: async (payload) => {
|
|
46
|
+
captured.sent = payload;
|
|
47
|
+
return { status: 'captured' };
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
Manager: managerView,
|
|
53
|
+
log: () => {},
|
|
54
|
+
error: (message) => captured.errors.push(message),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function runSubscription(Manager, discount, { isTrial = false } = {}) {
|
|
59
|
+
const captured = { errors: [] };
|
|
60
|
+
const order = {
|
|
61
|
+
id: 'ORD-PROMO-SUB',
|
|
62
|
+
type: 'subscription',
|
|
63
|
+
discount: discount,
|
|
64
|
+
unified: { product: { id: 'premium', name: 'Premium' }, payment: { price: PRICE, frequency: 'monthly' } },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
await newSubscription({
|
|
68
|
+
before: {},
|
|
69
|
+
after: {
|
|
70
|
+
product: { id: 'premium', name: 'Premium' },
|
|
71
|
+
payment: { frequency: 'monthly' },
|
|
72
|
+
trial: { claimed: isTrial },
|
|
73
|
+
},
|
|
74
|
+
order,
|
|
75
|
+
uid: UID,
|
|
76
|
+
userDoc: USER_DOC,
|
|
77
|
+
ctx: buildCtx(Manager, captured),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return { computed: captured.sent?.data?.content?._computed, captured };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function runOneTime(Manager, discount) {
|
|
84
|
+
const captured = { errors: [] };
|
|
85
|
+
const order = {
|
|
86
|
+
id: 'ORD-PROMO-ONE',
|
|
87
|
+
type: 'one-time',
|
|
88
|
+
discount: discount,
|
|
89
|
+
unified: { product: { id: 'credits-100', name: '100 Credits' }, payment: { price: PRICE } },
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
await purchaseCompleted({
|
|
93
|
+
before: {},
|
|
94
|
+
after: { product: { id: 'credits-100', name: '100 Credits' }, payment: { price: PRICE, resourceId: 'ch_test_promo' } },
|
|
95
|
+
order,
|
|
96
|
+
uid: UID,
|
|
97
|
+
userDoc: USER_DOC,
|
|
98
|
+
ctx: buildCtx(Manager, captured),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return { computed: captured.sent?.data?.content?._computed, captured };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = defineCases({
|
|
105
|
+
description: 'Order-confirmation transitions: promo line + totals per discount shape',
|
|
106
|
+
type: 'group',
|
|
107
|
+
timeout: 15000,
|
|
108
|
+
|
|
109
|
+
tests: [
|
|
110
|
+
{
|
|
111
|
+
name: 'a-percent-code-renders-a-percent-line',
|
|
112
|
+
async run({ assert, Manager }) {
|
|
113
|
+
const { computed } = await runSubscription(Manager, discountCodes.validate('WELCOME15'));
|
|
114
|
+
|
|
115
|
+
assert.ok(computed, 'The transition should have composed the email');
|
|
116
|
+
assert.equal(computed.promoCode, 'WELCOME15', 'The line names the code');
|
|
117
|
+
assert.equal(computed.promoPercent, 15, 'A percent code quotes its percent');
|
|
118
|
+
assert.equal(computed.promoSavings, '7.50', 'It saved 15% of the price');
|
|
119
|
+
assert.equal(computed.totalToday, '42.49', 'The total is what was actually charged');
|
|
120
|
+
assert.equal(computed.firstChargeAmount, '42.49', 'The first charge matches');
|
|
121
|
+
assert.equal('promoAmount' in computed, false, 'A percent code quotes no dollar amount');
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
{
|
|
126
|
+
name: 'an-amount-code-renders-a-money-line-and-the-discounted-total',
|
|
127
|
+
async run({ assert, Manager }) {
|
|
128
|
+
const { computed } = await runSubscription(Manager, discountCodes.validate('WELCOME10OFF'));
|
|
129
|
+
|
|
130
|
+
assert.equal(computed.promoCode, 'WELCOME10OFF', 'The line names the code');
|
|
131
|
+
assert.equal(computed.promoAmount, '10.00', 'A flat-dollar code quotes its dollars');
|
|
132
|
+
assert.equal(computed.promoSavings, '10.00', 'It saved the full $10');
|
|
133
|
+
assert.equal(computed.totalToday, '39.99', 'The receipt must not quote the list price');
|
|
134
|
+
assert.equal('promoPercent' in computed, false, 'An amount code quotes no percentage');
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
{
|
|
139
|
+
name: 'a-discount-with-neither-shape-renders-no-promo-line-and-does-not-throw',
|
|
140
|
+
async run({ assert, Manager }) {
|
|
141
|
+
// An order written before the amount field existed. The handler is
|
|
142
|
+
// dispatched fire-and-forget, so a throw here costs the email silently.
|
|
143
|
+
const { computed, captured } = await runSubscription(Manager, LEGACY_SHAPELESS_DISCOUNT);
|
|
144
|
+
|
|
145
|
+
assert.ok(computed, 'The email should still be composed');
|
|
146
|
+
assert.equal('promoCode' in computed, false, 'A shapeless discount renders no promo line');
|
|
147
|
+
assert.equal('promoPercent' in computed, false, 'Nothing to quote as a percentage');
|
|
148
|
+
assert.equal('promoAmount' in computed, false, 'Nothing to quote as an amount');
|
|
149
|
+
assert.equal(computed.totalToday, '49.99', 'With no usable discount the full price stands');
|
|
150
|
+
assert.deepEqual(captured.errors, [], 'The transition should log no error');
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
{
|
|
155
|
+
name: 'a-trial-still-charges-nothing-today',
|
|
156
|
+
async run({ assert, Manager }) {
|
|
157
|
+
const { computed } = await runSubscription(Manager, discountCodes.validate('WELCOME10OFF'), { isTrial: true });
|
|
158
|
+
|
|
159
|
+
assert.equal(computed.totalToday, '0.00', 'A trial charges nothing today');
|
|
160
|
+
assert.equal(computed.firstChargeAmount, '39.99', 'The first real charge is still the discounted one');
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
{
|
|
165
|
+
name: 'the-one-time-transition-behaves-the-same-for-every-shape',
|
|
166
|
+
async run({ assert, Manager }) {
|
|
167
|
+
const percent = await runOneTime(Manager, discountCodes.validate('FLASH20'));
|
|
168
|
+
assert.equal(percent.computed.promoPercent, 20, 'A percent code quotes its percent');
|
|
169
|
+
assert.equal(percent.computed.totalToday, '39.99', '20% off 49.99 is 39.99');
|
|
170
|
+
|
|
171
|
+
const amount = await runOneTime(Manager, discountCodes.validate('WELCOME10OFF'));
|
|
172
|
+
assert.equal(amount.computed.promoAmount, '10.00', 'A flat-dollar code quotes its dollars');
|
|
173
|
+
assert.equal(amount.computed.totalToday, '39.99', '$10 off 49.99 is 39.99');
|
|
174
|
+
|
|
175
|
+
const shapeless = await runOneTime(Manager, LEGACY_SHAPELESS_DISCOUNT);
|
|
176
|
+
assert.equal('promoCode' in shapeless.computed, false, 'A shapeless discount renders no promo line');
|
|
177
|
+
assert.equal(shapeless.computed.totalToday, '49.99', 'The full price stands');
|
|
178
|
+
assert.deepEqual(shapeless.captured.errors, [], 'The transition should log no error');
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
{
|
|
183
|
+
name: 'no-discount-at-all-is-unchanged',
|
|
184
|
+
async run({ assert, Manager }) {
|
|
185
|
+
const { computed } = await runSubscription(Manager, null);
|
|
186
|
+
|
|
187
|
+
assert.equal('promoCode' in computed, false, 'No code, no promo line');
|
|
188
|
+
assert.equal(computed.totalToday, '49.99', 'The customer pays the list price');
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
});
|