@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,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe webhook provider
|
|
3
|
+
* Extracts and categorizes webhook event data from Stripe
|
|
4
|
+
*
|
|
5
|
+
* Each event is mapped to a category (subscription or one-time) and includes
|
|
6
|
+
* the resource type + ID needed to fetch the latest state from Stripe's API.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Invoice events, successful and failed. A renewal produces NO subscription
|
|
10
|
+
// transition (active → active, same product), so the invoice event is the only
|
|
11
|
+
// thing that tells the pipeline money moved — without it Stripe recurring
|
|
12
|
+
// revenue never reaches analytics ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)).
|
|
13
|
+
//
|
|
14
|
+
// `invoice.paid` is deliberately NOT here. Stripe fires it alongside
|
|
15
|
+
// `invoice.payment_succeeded` for the same paid invoice, and the analytics
|
|
16
|
+
// resolver treats every renewal-shaped webhook as its own payment — ingesting
|
|
17
|
+
// both would report a renewal's revenue TWICE. `invoice.payment_succeeded` is
|
|
18
|
+
// the narrower of the two (a payment attempt actually succeeded), so it is the
|
|
19
|
+
// one that carries renewals. A brand must send `invoice.payment_succeeded`:
|
|
20
|
+
// `invoice.paid` is rejected at the route (`isSupported`) and never stored.
|
|
21
|
+
const INVOICE_EVENTS = new Set([
|
|
22
|
+
'invoice.payment_failed',
|
|
23
|
+
'invoice.payment_succeeded',
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
// Events we process, mapped to their default category
|
|
27
|
+
// Some events (the invoice events, checkout.session.completed) require
|
|
28
|
+
// inspecting the payload to determine the actual category
|
|
29
|
+
const SUPPORTED_EVENTS = new Set([
|
|
30
|
+
// Subscription lifecycle
|
|
31
|
+
'customer.subscription.created',
|
|
32
|
+
'customer.subscription.updated',
|
|
33
|
+
'customer.subscription.deleted',
|
|
34
|
+
|
|
35
|
+
// Invoice outcomes — renewals and failures (could be subscription or one-time)
|
|
36
|
+
...INVOICE_EVENTS,
|
|
37
|
+
|
|
38
|
+
// Checkout completion (could be subscription or one-time)
|
|
39
|
+
'checkout.session.completed',
|
|
40
|
+
|
|
41
|
+
// Refunds
|
|
42
|
+
'charge.refunded',
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
/**
|
|
47
|
+
* Returns true if this event type should be saved and processed
|
|
48
|
+
*/
|
|
49
|
+
isSupported(eventType) {
|
|
50
|
+
return SUPPORTED_EVENTS.has(eventType);
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Parse a Stripe webhook request
|
|
55
|
+
* Extracts event data and determines category, resource type, resource ID, and UID
|
|
56
|
+
*
|
|
57
|
+
* @param {object} req - The raw HTTP request
|
|
58
|
+
* @returns {object} { eventId, eventType, category, resourceType, resourceId, chargeId, raw, uid }
|
|
59
|
+
* - category: 'subscription' | 'one-time' | null (null = skip)
|
|
60
|
+
* - resourceType: 'subscription' | 'invoice' | 'session' | 'charge'
|
|
61
|
+
* - resourceId: ID to fetch from provider API
|
|
62
|
+
* - chargeId: THIS charge's own id, where a subscription event names one —
|
|
63
|
+
* Stripe's invoice id. The resourceId is the subscription, which is
|
|
64
|
+
* constant for its whole life, so it can never key a single charge
|
|
65
|
+
* ([#656](https://github.com/Omega-JS-Stack/omega/issues/656)).
|
|
66
|
+
*/
|
|
67
|
+
parseWebhook(req) {
|
|
68
|
+
const event = req.body;
|
|
69
|
+
|
|
70
|
+
// Validate event structure
|
|
71
|
+
if (!event || !event.id || !event.type) {
|
|
72
|
+
throw new Error('Invalid Stripe webhook payload');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const dataObject = event.data?.object || {};
|
|
76
|
+
const eventType = event.type;
|
|
77
|
+
|
|
78
|
+
// Resolve category, resource info, and UID based on event type
|
|
79
|
+
let category = null;
|
|
80
|
+
let resourceType = null;
|
|
81
|
+
let resourceId = null;
|
|
82
|
+
let uid = null;
|
|
83
|
+
// The invoice this event is about, when it is about one. A one-time purchase
|
|
84
|
+
// has exactly one charge and the order names it, so only the SUBSCRIPTION
|
|
85
|
+
// branches fill this in ([#656]).
|
|
86
|
+
let chargeId = null;
|
|
87
|
+
|
|
88
|
+
if (eventType.startsWith('customer.subscription.')) {
|
|
89
|
+
// Subscription lifecycle events — always subscription category
|
|
90
|
+
category = 'subscription';
|
|
91
|
+
resourceType = 'subscription';
|
|
92
|
+
resourceId = dataObject.id;
|
|
93
|
+
uid = dataObject.metadata?.uid || null;
|
|
94
|
+
|
|
95
|
+
} else if (INVOICE_EVENTS.has(eventType)) {
|
|
96
|
+
// Invoice outcome (renewal or failure) — inspect billing_reason to determine
|
|
97
|
+
// category. A subscription invoice resolves to the SUBSCRIPTION it belongs
|
|
98
|
+
// to, so the pipeline re-fetches live subscription state either way.
|
|
99
|
+
const billingReason = dataObject.billing_reason || '';
|
|
100
|
+
const subscriptionId = dataObject.parent?.subscription_details?.subscription
|
|
101
|
+
|| dataObject.subscription
|
|
102
|
+
|| null;
|
|
103
|
+
|
|
104
|
+
if (billingReason.startsWith('subscription') && subscriptionId) {
|
|
105
|
+
// Subscription-related invoice
|
|
106
|
+
category = 'subscription';
|
|
107
|
+
resourceType = 'subscription';
|
|
108
|
+
resourceId = subscriptionId;
|
|
109
|
+
// The invoice IS the charge — one per renewal, recovery and conversion.
|
|
110
|
+
chargeId = dataObject.id || null;
|
|
111
|
+
uid = dataObject.parent?.subscription_details?.metadata?.uid
|
|
112
|
+
|| dataObject.subscription_details?.metadata?.uid
|
|
113
|
+
|| dataObject.metadata?.uid
|
|
114
|
+
|| null;
|
|
115
|
+
} else {
|
|
116
|
+
// One-time (manual) invoice
|
|
117
|
+
category = 'one-time';
|
|
118
|
+
resourceType = 'invoice';
|
|
119
|
+
resourceId = dataObject.id;
|
|
120
|
+
uid = dataObject.metadata?.uid || null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
} else if (eventType === 'checkout.session.completed') {
|
|
124
|
+
const mode = dataObject.mode;
|
|
125
|
+
|
|
126
|
+
if (mode === 'subscription') {
|
|
127
|
+
// Subscription checkout — skip, subscription events handle this
|
|
128
|
+
category = null;
|
|
129
|
+
} else if (mode === 'payment') {
|
|
130
|
+
// One-time payment checkout
|
|
131
|
+
category = 'one-time';
|
|
132
|
+
resourceType = 'session';
|
|
133
|
+
resourceId = dataObject.id;
|
|
134
|
+
uid = dataObject.metadata?.uid || null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
} else if (eventType === 'charge.refunded') {
|
|
138
|
+
// Refund event — the charge object contains an invoice ID which links to a subscription
|
|
139
|
+
const invoiceId = dataObject.invoice;
|
|
140
|
+
const subscriptionId = dataObject.subscription
|
|
141
|
+
|| dataObject.metadata?.subscriptionId
|
|
142
|
+
|| null;
|
|
143
|
+
|
|
144
|
+
if (subscriptionId) {
|
|
145
|
+
// Subscription-related refund
|
|
146
|
+
category = 'subscription';
|
|
147
|
+
resourceType = 'subscription';
|
|
148
|
+
resourceId = subscriptionId;
|
|
149
|
+
// The invoice the reversed charge was paid against, so the refund can
|
|
150
|
+
// name the same id GA4 recorded that charge under ([#656]).
|
|
151
|
+
chargeId = invoiceId || null;
|
|
152
|
+
} else if (invoiceId) {
|
|
153
|
+
// Has invoice — likely subscription-related, will resolve via fetchResource
|
|
154
|
+
category = 'subscription';
|
|
155
|
+
resourceType = 'invoice';
|
|
156
|
+
resourceId = invoiceId;
|
|
157
|
+
chargeId = invoiceId;
|
|
158
|
+
} else {
|
|
159
|
+
// One-time payment refund — no subscription, no invoice, so the charge
|
|
160
|
+
// itself is the resource. Dropping it (category = null) meant the refund
|
|
161
|
+
// of a one-time purchase never entered the pipeline at all
|
|
162
|
+
// ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)).
|
|
163
|
+
category = 'one-time';
|
|
164
|
+
resourceType = 'charge';
|
|
165
|
+
resourceId = dataObject.id;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
uid = dataObject.metadata?.uid || null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
eventId: event.id,
|
|
173
|
+
eventType: eventType,
|
|
174
|
+
category: category,
|
|
175
|
+
resourceType: resourceType,
|
|
176
|
+
resourceId: resourceId,
|
|
177
|
+
chargeId: chargeId,
|
|
178
|
+
raw: event,
|
|
179
|
+
uid: uid,
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test webhook provider
|
|
3
|
+
* Delegates to Stripe's parser since test provider generates Stripe-shaped event payloads
|
|
4
|
+
*
|
|
5
|
+
* Only the parser is delegated: these events are FABRICATED locally, and the
|
|
6
|
+
* route's production guard is what keeps this provider out of production.
|
|
7
|
+
*/
|
|
8
|
+
const stripeProvider = require('./stripe.js');
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
isSupported(eventType) {
|
|
12
|
+
return stripeProvider.isSupported(eventType);
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
parseWebhook(req) {
|
|
16
|
+
return stripeProvider.parseWebhook(req);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const powertools = require('node-powertools');
|
|
3
|
+
const loadProvider = require('../../../libraries/load-provider.js');
|
|
4
|
+
const winback = require('../../../libraries/payment/winback.js');
|
|
5
|
+
const isTrialing = require('../cancel/_is-trialing.js');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* POST /payments/winback
|
|
9
|
+
* Applies the cancel-flow SAVE OFFER to the authenticated user's live
|
|
10
|
+
* subscription, so the cancel they started never happens
|
|
11
|
+
* ([#268](https://github.com/Omega-JS-Stack/omega/issues/268)).
|
|
12
|
+
*
|
|
13
|
+
* The offer is the brand's (`payment.winback` in omega.json5 — 50% off the next
|
|
14
|
+
* cycle by default) and it reaches the provider as a discount, through the same
|
|
15
|
+
* coupon plumbing a checkout discount code rides. The subscription itself does
|
|
16
|
+
* not change: the customer keeps the plan, the cadence and the renewal date they
|
|
17
|
+
* already had, and the next invoice is the only thing that moves — so the only
|
|
18
|
+
* thing this route writes onto the account is the discount itself
|
|
19
|
+
* (`subscription.discount`, [#325]), never the plan, the cadence or the renewal.
|
|
20
|
+
*
|
|
21
|
+
* Claimed ONCE per subscription: the claim is recorded on
|
|
22
|
+
* payments-orders/{orderId}.requests.winback, which is also what a second call
|
|
23
|
+
* is refused against (`offer-already-claimed`) — an offer that could be taken
|
|
24
|
+
* every time the cancel dialog opens is a permanent discount nobody agreed to.
|
|
25
|
+
* A subscription with no order doc has nowhere to record it, so it is refused
|
|
26
|
+
* (`offer-not-claimable`) rather than handed an offer with no memory.
|
|
27
|
+
*
|
|
28
|
+
* Cross-provider and CAPABILITY-GATED, the same shape uncancel uses: a provider
|
|
29
|
+
* that can discount a live subscription exports applyOffer(), one that cannot
|
|
30
|
+
* simply lacks the export, and the route refuses before dispatch rather than
|
|
31
|
+
* letting the caller discover it as a provider error
|
|
32
|
+
* ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)).
|
|
33
|
+
*
|
|
34
|
+
* EVERY refusal here carries a machine-readable code on the response properties
|
|
35
|
+
* (`additional.code`), not just the capability gate's
|
|
36
|
+
* ([#311](https://github.com/Omega-JS-Stack/omega/issues/311)): the client
|
|
37
|
+
* pitches the offer off the ACCOUNT alone, so a state it cannot see — an
|
|
38
|
+
* admin-granted subscription with no provider details, a brand that turned the
|
|
39
|
+
* offer off since the page loaded — reaches accept, and a refusal it cannot name
|
|
40
|
+
* leaves the customer in a dialog arming a retry that can never succeed. The
|
|
41
|
+
* codes, in the order they are refused: `confirmation-required`,
|
|
42
|
+
* `offer-disabled`, `no-active-subscription`, `trial-not-eligible`,
|
|
43
|
+
* `cancellation-pending`, `missing-payment-details`, `unknown-provider`,
|
|
44
|
+
* `not-supported-by-provider`, `offer-not-claimable`, `offer-already-claimed`.
|
|
45
|
+
* All but the first are dead ends for that account: the billing card retires the
|
|
46
|
+
* offer on them and opens the questionnaire the customer came for.
|
|
47
|
+
* Requires authentication.
|
|
48
|
+
*/
|
|
49
|
+
module.exports = async ({ ctx, user, settings }) => {
|
|
50
|
+
// Require authentication
|
|
51
|
+
if (!user.authenticated) {
|
|
52
|
+
return ctx.respond('Authentication required', { code: 401 });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const uid = user.auth.uid;
|
|
56
|
+
const confirmed = settings.confirmed;
|
|
57
|
+
|
|
58
|
+
// Require explicit confirmation
|
|
59
|
+
if (!confirmed) {
|
|
60
|
+
return ctx.respond('Accepting the offer must be confirmed', {
|
|
61
|
+
code: 400,
|
|
62
|
+
additional: { code: 'confirmation-required' },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// The brand's own offer. A brand that turned it off has no offer to apply, and
|
|
67
|
+
// the client never shows the step — so a call arriving here is a stale page or
|
|
68
|
+
// a hand-rolled request, and it is refused rather than given a default.
|
|
69
|
+
const offer = winback.resolveOffer(ctx.Manager.config);
|
|
70
|
+
|
|
71
|
+
if (!offer.enabled) {
|
|
72
|
+
ctx.log(`Winback rejected: uid=${uid}, the save offer is disabled for this brand`);
|
|
73
|
+
return ctx.respond('This offer is not available', {
|
|
74
|
+
code: 400,
|
|
75
|
+
additional: { code: 'offer-disabled' },
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const subscription = user.subscription;
|
|
80
|
+
|
|
81
|
+
// Require an ACTIVE paid subscription — there is no next cycle to discount on
|
|
82
|
+
// a suspended or already-ended one
|
|
83
|
+
if (!subscription || subscription.status !== 'active' || subscription.product?.id === 'basic') {
|
|
84
|
+
ctx.log(`Winback rejected: uid=${uid}, status=${subscription?.status}, product=${subscription?.product?.id}`);
|
|
85
|
+
return ctx.respond('No active paid subscription found', {
|
|
86
|
+
code: 400,
|
|
87
|
+
additional: { code: 'no-active-subscription' },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// A TRIAL is never offered this: cancelling a trial ends access immediately
|
|
92
|
+
// (#267) and nothing has been paid, so "off your next cycle" is not the offer
|
|
93
|
+
// that state needs. The billing card gates the same way, off the same rule.
|
|
94
|
+
if (isTrialing(subscription)) {
|
|
95
|
+
ctx.log(`Winback rejected: uid=${uid}, subscription is still in its free trial`);
|
|
96
|
+
return ctx.respond('This offer is not available on a free trial', {
|
|
97
|
+
code: 400,
|
|
98
|
+
additional: { code: 'trial-not-eligible' },
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// The offer is made BEFORE the questionnaire, so a subscription already
|
|
103
|
+
// scheduled to end is past it. Undo cancellation is the honest verb there.
|
|
104
|
+
if (subscription.cancellation?.pending === true) {
|
|
105
|
+
ctx.log(`Winback rejected: uid=${uid}, cancellation already pending`);
|
|
106
|
+
return ctx.respond('Your subscription is already scheduled to cancel', {
|
|
107
|
+
code: 400,
|
|
108
|
+
additional: { code: 'cancellation-pending' },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const provider = subscription.payment?.provider;
|
|
113
|
+
const resourceId = subscription.payment?.resourceId;
|
|
114
|
+
|
|
115
|
+
// A paid, active subscription can still carry NO provider details at all —
|
|
116
|
+
// granted by an admin, imported, a webhook backfill that never landed — and
|
|
117
|
+
// the client pitches what the account says, which is "paid and active". There
|
|
118
|
+
// is nothing to send a discount to, and no retry adds the details, so the
|
|
119
|
+
// refusal is a dead end the billing card retires the offer on ([#311]).
|
|
120
|
+
if (!provider || !resourceId) {
|
|
121
|
+
ctx.log(`Winback rejected: uid=${uid}, missing provider=${provider} or resourceId=${resourceId}`);
|
|
122
|
+
return ctx.respond('Subscription payment details not found', {
|
|
123
|
+
code: 400,
|
|
124
|
+
additional: { code: 'missing-payment-details' },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Load the provider module
|
|
129
|
+
let providerModule;
|
|
130
|
+
try {
|
|
131
|
+
providerModule = loadProvider(path.join(__dirname, 'providers'), provider);
|
|
132
|
+
} catch (e) {
|
|
133
|
+
return ctx.respond(`Unknown provider: ${provider}`, {
|
|
134
|
+
code: 400,
|
|
135
|
+
additional: { code: 'unknown-provider' },
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// The capability gate. A missing export is the provider saying it cannot
|
|
140
|
+
// discount a live subscription at all — a CLIENT fault to be branched on, not
|
|
141
|
+
// an outage to retry, so the code rides the response properties where every
|
|
142
|
+
// 4xx carries its machine-readable half, and the billing card retires the
|
|
143
|
+
// offer and lets the cancel through on it.
|
|
144
|
+
if (typeof providerModule.applyOffer !== 'function') {
|
|
145
|
+
ctx.log(`Winback not supported: uid=${uid}, provider=${provider}`);
|
|
146
|
+
return ctx.respond('Your payment provider cannot apply this offer. Please use the billing portal to manage your subscription.', {
|
|
147
|
+
code: 400,
|
|
148
|
+
additional: { code: 'not-supported-by-provider' },
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// One claim per subscription. The order doc is where the claim lives, so the
|
|
153
|
+
// check reads the same document the write below lands on.
|
|
154
|
+
//
|
|
155
|
+
// No order doc, no claim — and an offer whose claim cannot be RECORDED is an
|
|
156
|
+
// offer takeable every time the cancel dialog opens, each accept re-couponing
|
|
157
|
+
// the subscription. A subscription can reach here without one (created in the
|
|
158
|
+
// provider's dashboard, imported, a metadata backfill that never landed), so
|
|
159
|
+
// it is refused before dispatch rather than handed an offer this route cannot
|
|
160
|
+
// remember. The code rides the response properties the capability gate's does,
|
|
161
|
+
// so the billing card branches on it and lets the cancel through. It is read
|
|
162
|
+
// AFTER that gate: a provider that cannot discount at all is the more
|
|
163
|
+
// permanent answer, and it costs no read.
|
|
164
|
+
const orderId = subscription.payment?.orderId;
|
|
165
|
+
|
|
166
|
+
if (!orderId) {
|
|
167
|
+
ctx.log(`Winback rejected: uid=${uid}, the subscription carries no orderId to record the claim on`);
|
|
168
|
+
return ctx.respond('This offer is not available on your subscription. Please use the billing portal to manage your subscription.', {
|
|
169
|
+
code: 400,
|
|
170
|
+
additional: { code: 'offer-not-claimable' },
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const admin = ctx.Manager.libraries.admin;
|
|
175
|
+
const orderRef = admin.firestore().doc(`payments-orders/${orderId}`);
|
|
176
|
+
const orderDoc = await orderRef.get();
|
|
177
|
+
|
|
178
|
+
// A past claimant reaching the cancel flow again is pitched the offer anyway
|
|
179
|
+
// — the client reads the ACCOUNT, which carries no claim — so this refusal
|
|
180
|
+
// rides the same branchable code the two gates above do ([#310]). Without
|
|
181
|
+
// one, accepting shows an error toast and leaves the dialog armed for a retry
|
|
182
|
+
// that can never succeed; with it the billing card retires the offer and
|
|
183
|
+
// opens the questionnaire, which is what the customer came for.
|
|
184
|
+
if (orderDoc.exists && orderDoc.data().requests?.winback) {
|
|
185
|
+
ctx.log(`Winback rejected: uid=${uid}, offer already claimed on payments-orders/${orderId}`);
|
|
186
|
+
return ctx.respond('You have already claimed this offer', {
|
|
187
|
+
code: 400,
|
|
188
|
+
additional: { code: 'offer-already-claimed' },
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// The offer, in the shape every downstream reader already speaks
|
|
193
|
+
const discount = winback.toDiscount(offer);
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
await providerModule.applyOffer({ resourceId, uid, subscription, discount, ctx });
|
|
197
|
+
} catch (e) {
|
|
198
|
+
// The provider's own words stay in the logs — a client gets one neutral
|
|
199
|
+
// sentence, never an SDK message naming our internals ([#212]).
|
|
200
|
+
ctx.error(`Failed to apply the winback offer via ${provider}: uid=${uid}, sub=${resourceId}, error=${e.message}`);
|
|
201
|
+
return ctx.respond('We could not apply your discount right now. Please try again shortly.', { code: 500 });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Record the claim. This is the offer's whole memory: the refusal above reads
|
|
205
|
+
// it, and it is what an analysis of the experiment counts accepts from.
|
|
206
|
+
const now = powertools.timestamp(new Date(), { output: 'string' });
|
|
207
|
+
const nowUNIX = powertools.timestamp(now, { output: 'unix' });
|
|
208
|
+
|
|
209
|
+
await orderRef.set({
|
|
210
|
+
requests: {
|
|
211
|
+
winback: {
|
|
212
|
+
discount: discount,
|
|
213
|
+
date: {
|
|
214
|
+
timestamp: now,
|
|
215
|
+
timestampUNIX: nowUNIX,
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
}, { merge: true });
|
|
220
|
+
|
|
221
|
+
ctx.log(`Stored winback claim on payments-orders/${orderId}: code=${discount.code}`);
|
|
222
|
+
|
|
223
|
+
// The ACCOUNT's half of the same claim ([#325]). The order doc is the offer's
|
|
224
|
+
// memory — what a second claim is refused against — but the billing card reads
|
|
225
|
+
// the account, and a saving that disappears on the next page load was never
|
|
226
|
+
// announced at all. The subscription itself still does not change: this is the
|
|
227
|
+
// discount riding it, not a new plan, a new cadence or a new renewal date.
|
|
228
|
+
//
|
|
229
|
+
// EVERY field is written, never the validate() result's own half-shape: the
|
|
230
|
+
// node can already carry a checkout code's discount, and a percent claim
|
|
231
|
+
// merging onto a stored amount would be read as the older, wrong number. And
|
|
232
|
+
// `source` is what makes the node safe to read as a claim at all — a checkout
|
|
233
|
+
// code sets the same shape, so only 'winback' is the cancel flow's signal.
|
|
234
|
+
//
|
|
235
|
+
// `resourceId` is the subscription it was applied TO, and it is what lets the
|
|
236
|
+
// claim ever END ([#333]). The unified webhook write carries no discount key,
|
|
237
|
+
// so the merge preserves this node forever: without the stamp, a customer who
|
|
238
|
+
// churned and resubscribed carried a spent claim into the new subscription,
|
|
239
|
+
// where `source: 'winback'` reads as "already claimed" and the save offer is
|
|
240
|
+
// silently never pitched again. Stamped, the webhook pipeline clears the node
|
|
241
|
+
// the moment the account's subscription is a different one.
|
|
242
|
+
await admin.firestore().doc(`users/${uid}`).set({
|
|
243
|
+
subscription: {
|
|
244
|
+
discount: {
|
|
245
|
+
valid: true,
|
|
246
|
+
code: discount.code,
|
|
247
|
+
percent: discount.percent || 0,
|
|
248
|
+
amount: discount.amount || 0,
|
|
249
|
+
duration: discount.duration,
|
|
250
|
+
source: 'winback',
|
|
251
|
+
resourceId: resourceId,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
}, { merge: true });
|
|
255
|
+
|
|
256
|
+
ctx.log(`Stored the applied discount on users/${uid}: code=${discount.code}, sub=${resourceId}`);
|
|
257
|
+
|
|
258
|
+
// The experiment's server-side half. The offer is measured against the
|
|
259
|
+
// existing `subscription-winback` baseline (a returning subscriber the webhook
|
|
260
|
+
// pipeline already reads as a purchase), so the ACCEPT is recorded where that
|
|
261
|
+
// pipeline's events go — the client counts shown/declined, which never reach a
|
|
262
|
+
// server at all.
|
|
263
|
+
ctx.analytics.event('payments/winback', {
|
|
264
|
+
code: discount.code,
|
|
265
|
+
percent: discount.percent || null,
|
|
266
|
+
amount: discount.amount || null,
|
|
267
|
+
duration: discount.duration,
|
|
268
|
+
payment_provider: provider,
|
|
269
|
+
product_id: subscription.product?.id || null,
|
|
270
|
+
payment_frequency: subscription.payment?.frequency || null,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
ctx.log(`Winback offer applied: uid=${uid}, provider=${provider}, sub=${resourceId}, code=${discount.code}, duration=${discount.duration}`);
|
|
274
|
+
|
|
275
|
+
return ctx.respond({ success: true, discount: discount });
|
|
276
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chargebee winback provider — DELIBERATELY EMPTY, for now.
|
|
3
|
+
*
|
|
4
|
+
* Chargebee DOES have coupons, and the checkout already creates them
|
|
5
|
+
* (resolveChargebeeCoupon in routes/payments/intent/providers/chargebee.js).
|
|
6
|
+
* What it has no existing plumbing for is attaching one to a subscription that
|
|
7
|
+
* is already running: the only verb this framework drives on a live Chargebee
|
|
8
|
+
* subscription is `update_for_items`, which REPLACES the subscription's items
|
|
9
|
+
* with whatever is sent (see the plan-switch provider). Carrying a coupon
|
|
10
|
+
* through it would mean reading the live item set back and restating it on every
|
|
11
|
+
* offer — a re-pricing risk taken for a discount — and any other route to it is
|
|
12
|
+
* provider surface nothing here has proven
|
|
13
|
+
* ([#268](https://github.com/Omega-JS-Stack/omega/issues/268)).
|
|
14
|
+
*
|
|
15
|
+
* So Chargebee declares the capability it has today, which is none. The module
|
|
16
|
+
* exports NOTHING on purpose: the gate in ../post.js reads
|
|
17
|
+
* `typeof providerModule.applyOffer === 'function'`, the caller gets a
|
|
18
|
+
* `not-supported-by-provider` 400, and the billing card retires the offer and
|
|
19
|
+
* opens the questionnaire — a Chargebee subscriber can always still cancel.
|
|
20
|
+
*
|
|
21
|
+
* The file still has to EXIST: without it the route would answer "Unknown
|
|
22
|
+
* provider", which is a different (and wrong) statement about Chargebee.
|
|
23
|
+
*/
|
|
24
|
+
module.exports = {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PayPal winback provider — DELIBERATELY EMPTY.
|
|
3
|
+
*
|
|
4
|
+
* PayPal has no coupon or discount object at all. A subscription's price is the
|
|
5
|
+
* PLAN's price, and the only ways to change what a subscriber pays next are to
|
|
6
|
+
* revise them onto a different plan (which is a plan switch, not a one-cycle
|
|
7
|
+
* discount, and would leave them there) or to write a one-off pricing scheme
|
|
8
|
+
* onto the plan itself — which would move every subscriber on it. Neither is the
|
|
9
|
+
* offer, and neither rides plumbing that already exists here: the checkout's
|
|
10
|
+
* discount codes have never reached PayPal either
|
|
11
|
+
* ([#268](https://github.com/Omega-JS-Stack/omega/issues/268)).
|
|
12
|
+
*
|
|
13
|
+
* The module exports NOTHING on purpose: the capability gate in ../post.js reads
|
|
14
|
+
* `typeof providerModule.applyOffer === 'function'`, so the absent export IS the
|
|
15
|
+
* declaration, and the caller gets a `not-supported-by-provider` 400 that the
|
|
16
|
+
* billing card turns into "the offer is retired, here is the questionnaire"
|
|
17
|
+
* rather than a dead dialog ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)).
|
|
18
|
+
*
|
|
19
|
+
* The file still has to EXIST: without it the route would answer "Unknown
|
|
20
|
+
* provider", which is a different (and wrong) statement about PayPal.
|
|
21
|
+
*/
|
|
22
|
+
module.exports = {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe winback provider
|
|
3
|
+
* Applies the save offer to a live subscription as a coupon.
|
|
4
|
+
*
|
|
5
|
+
* The coupon is the SAME object a checkout discount code creates — deterministic
|
|
6
|
+
* id, created once, reused forever (StripeLib.resolveCoupon) — and attaching it
|
|
7
|
+
* to the subscription is what makes the next invoice cheaper. A `once` coupon
|
|
8
|
+
* discounts exactly the next cycle and then falls away on its own; a `forever`
|
|
9
|
+
* one is the permanent cut a brand asked for in config.
|
|
10
|
+
*
|
|
11
|
+
* The subscription is otherwise untouched: same price, same interval, same
|
|
12
|
+
* renewal date. Stripe then sends customer.subscription.updated, which the
|
|
13
|
+
* existing pipeline processes.
|
|
14
|
+
*/
|
|
15
|
+
module.exports = {
|
|
16
|
+
/**
|
|
17
|
+
* Apply the save offer to a Stripe subscription
|
|
18
|
+
*
|
|
19
|
+
* @param {object} options
|
|
20
|
+
* @param {string} options.resourceId - Stripe subscription ID (e.g., 'sub_xxx')
|
|
21
|
+
* @param {string} options.uid - User's UID (for logging)
|
|
22
|
+
* @param {object} options.subscription - User's current subscription object
|
|
23
|
+
* @param {object} options.discount - The offer as a discount-codes validate() result
|
|
24
|
+
* @param {object} options.ctx - Assistant instance for logging
|
|
25
|
+
*/
|
|
26
|
+
async applyOffer({ resourceId, uid, discount, ctx }) {
|
|
27
|
+
const StripeLib = require('../../../../libraries/payment/providers/stripe.js');
|
|
28
|
+
const stripe = StripeLib.init();
|
|
29
|
+
|
|
30
|
+
const couponId = await StripeLib.resolveCoupon(discount, ctx);
|
|
31
|
+
|
|
32
|
+
// `discounts` REPLACES every discount already on the subscription — it is
|
|
33
|
+
// the whole list, not an addition — so an existing coupon (a retention
|
|
34
|
+
// credit, an earlier offer) is dropped when this one lands.
|
|
35
|
+
await stripe.subscriptions.update(resourceId, {
|
|
36
|
+
discounts: [{ coupon: couponId }],
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
ctx.log(`Stripe winback offer applied: sub=${resourceId}, uid=${uid}, coupon=${couponId}`);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test winback provider
|
|
3
|
+
* Applies the save offer the way the real ones do: to the PROVIDER, not to us.
|
|
4
|
+
*
|
|
5
|
+
* The other test providers write a payments-webhooks doc, because the thing
|
|
6
|
+
* they simulate changes subscription state and the pipeline is what writes it.
|
|
7
|
+
* A coupon changes none: the plan, the cadence and the renewal date all stay
|
|
8
|
+
* exactly as they were, and the only thing that moves is the next invoice, which
|
|
9
|
+
* this framework does not model. Minting a webhook here would put an event
|
|
10
|
+
* through the pipeline that resolves to no transition at all — noise that reads
|
|
11
|
+
* like a bug the first time someone finds it in the logs.
|
|
12
|
+
*
|
|
13
|
+
* So this provider does what Stripe's does to OUR data, which is nothing, and
|
|
14
|
+
* says so. A local QA run through `_dev_cardProvider=test` still proves the
|
|
15
|
+
* whole flow end to end — the gate, the dialog, the route's guards, the claim
|
|
16
|
+
* written on payments-orders/{orderId} — against exactly the data a real
|
|
17
|
+
* provider leaves behind
|
|
18
|
+
* ([#268](https://github.com/Omega-JS-Stack/omega/issues/268)).
|
|
19
|
+
*
|
|
20
|
+
* Only available in non-production environments.
|
|
21
|
+
*/
|
|
22
|
+
module.exports = {
|
|
23
|
+
/**
|
|
24
|
+
* Apply the save offer to a test subscription
|
|
25
|
+
*
|
|
26
|
+
* @param {object} options
|
|
27
|
+
* @param {string} options.resourceId - Test subscription ID
|
|
28
|
+
* @param {string} options.uid - User's UID (for logging)
|
|
29
|
+
* @param {object} options.subscription - User's current subscription object
|
|
30
|
+
* @param {object} options.discount - The offer as a discount-codes validate() result
|
|
31
|
+
* @param {object} options.ctx - Assistant instance for logging
|
|
32
|
+
*/
|
|
33
|
+
async applyOffer({ resourceId, uid, discount, ctx }) {
|
|
34
|
+
if (ctx.isProduction()) {
|
|
35
|
+
throw new Error('Test provider is not available in production');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const off = discount.amount > 0 ? `${discount.amount} off` : `${discount.percent}%`;
|
|
39
|
+
|
|
40
|
+
ctx.log(`Test winback provider: applied ${discount.code} (${off}, ${discount.duration}) to sub=${resourceId}, uid=${uid}`);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const jetpack = require('fs-jetpack');
|
|
2
|
+
|
|
3
|
+
module.exports = async ({ ctx, user, analytics }) => {
|
|
4
|
+
|
|
5
|
+
// Send analytics event
|
|
6
|
+
analytics.event('restart', {});
|
|
7
|
+
|
|
8
|
+
// Require authentication
|
|
9
|
+
if (!user.authenticated) {
|
|
10
|
+
return ctx.respond('Authentication required', { code: 401 });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Require admin
|
|
14
|
+
if (!user.roles.admin) {
|
|
15
|
+
return ctx.respond('Admin required', { code: 403 });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Log
|
|
19
|
+
ctx.log('Restarting...');
|
|
20
|
+
|
|
21
|
+
// Remove node_modules
|
|
22
|
+
jetpack.remove('node_modules');
|
|
23
|
+
|
|
24
|
+
// Perform delayed refresh to allow a successful response
|
|
25
|
+
setTimeout(function () {
|
|
26
|
+
require('child_process').exec('refresh', (error, stdout, stderr) => {
|
|
27
|
+
// Quit the process if there is an error
|
|
28
|
+
if (error || stderr) {
|
|
29
|
+
console.log(`error: ${error ? error.message : stderr}`);
|
|
30
|
+
return process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}, 1000);
|
|
34
|
+
|
|
35
|
+
// Return success
|
|
36
|
+
return ctx.respond({success: true});
|
|
37
|
+
};
|