@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,755 @@
|
|
|
1
|
+
const powertools = require('node-powertools');
|
|
2
|
+
const fetchFailure = require('../fetch-failure.js');
|
|
3
|
+
const assertRefundLinkage = require('../refund-linkage.js');
|
|
4
|
+
const env = require('../../env.js');
|
|
5
|
+
const assertLicensedPayments = require('../license.js');
|
|
6
|
+
|
|
7
|
+
// Lazy singleton Stripe SDK instance
|
|
8
|
+
let stripeInstance = null;
|
|
9
|
+
|
|
10
|
+
// Epoch zero timestamps (used as default/empty dates)
|
|
11
|
+
const EPOCH_ZERO = powertools.timestamp(new Date(0), { output: 'string' });
|
|
12
|
+
const EPOCH_ZERO_UNIX = powertools.timestamp(EPOCH_ZERO, { output: 'unix' });
|
|
13
|
+
|
|
14
|
+
// Stripe interval → unified frequency map
|
|
15
|
+
const INTERVAL_TO_FREQUENCY = { year: 'annually', month: 'monthly', week: 'weekly', day: 'daily' };
|
|
16
|
+
const FREQUENCY_TO_INTERVAL = { annually: 'year', monthly: 'month', weekly: 'week', daily: 'day' };
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Stripe shared library
|
|
20
|
+
* Provides SDK initialization, resource fetching, and unified transformations
|
|
21
|
+
*/
|
|
22
|
+
const Stripe = {
|
|
23
|
+
/**
|
|
24
|
+
* Initialize or return the Stripe SDK instance
|
|
25
|
+
* @param {string} secretKey - Stripe secret key
|
|
26
|
+
* @returns {object} Stripe SDK instance
|
|
27
|
+
*/
|
|
28
|
+
init() {
|
|
29
|
+
// A keyless deploy runs no live payments (#320) — before the SDK, and
|
|
30
|
+
// before the cached instance below can hand one back
|
|
31
|
+
assertLicensedPayments('Stripe');
|
|
32
|
+
|
|
33
|
+
if (!stripeInstance) {
|
|
34
|
+
const secretKey = env.get('STRIPE_SECRET_KEY');
|
|
35
|
+
|
|
36
|
+
if (!secretKey) {
|
|
37
|
+
throw new Error('STRIPE_SECRET_KEY environment variable is required');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
stripeInstance = new (require('stripe'))(secretKey);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return stripeInstance;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Fetch the latest resource from Stripe's API
|
|
48
|
+
* Stripe's answer is the only trusted source — a lookup that fails throws the
|
|
49
|
+
* classified failure ([../fetch-failure.js](../fetch-failure.js)) instead of
|
|
50
|
+
* degrading to the webhook payload
|
|
51
|
+
*
|
|
52
|
+
* @param {string} resourceType - 'subscription' | 'invoice' | 'session' | 'charge'
|
|
53
|
+
* @param {string} resourceId - Stripe resource ID
|
|
54
|
+
* @param {object} context - Additional context (e.g., { admin })
|
|
55
|
+
* @returns {object} Full Stripe resource object
|
|
56
|
+
*/
|
|
57
|
+
async fetchResource(resourceType, resourceId, context) {
|
|
58
|
+
const stripe = this.init();
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
if (resourceType === 'subscription') {
|
|
62
|
+
return await stripe.subscriptions.retrieve(resourceId);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (resourceType === 'invoice') {
|
|
66
|
+
return await stripe.invoices.retrieve(resourceId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (resourceType === 'session') {
|
|
70
|
+
return await stripe.checkout.sessions.retrieve(resourceId);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (resourceType === 'charge') {
|
|
74
|
+
// The refund of a one-time purchase carries the charge and nothing else.
|
|
75
|
+
// A charge inherits its metadata from the PaymentIntent that created it,
|
|
76
|
+
// so expand the intent: when the charge itself carries none, the intent
|
|
77
|
+
// is the only place uid/orderId/productId live
|
|
78
|
+
// ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)).
|
|
79
|
+
const charge = await stripe.charges.retrieve(resourceId, { expand: ['payment_intent'] });
|
|
80
|
+
const intentMetadata = charge.payment_intent?.metadata;
|
|
81
|
+
|
|
82
|
+
if (intentMetadata) {
|
|
83
|
+
return { ...charge, metadata: { ...intentMetadata, ...charge.metadata } };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return charge;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
throw new Error(`Unknown resource type: ${resourceType}`);
|
|
90
|
+
} catch (e) {
|
|
91
|
+
throw fetchFailure(e, { provider: 'stripe', fn: 'fetchResource', resourceType, resourceId });
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Extract the resource a Stripe webhook envelope carries
|
|
97
|
+
* Identifiers only — the payload never drives state ([../fetch-failure.js](../fetch-failure.js))
|
|
98
|
+
*
|
|
99
|
+
* @param {object} raw - Raw Stripe webhook payload
|
|
100
|
+
* @returns {object|null}
|
|
101
|
+
*/
|
|
102
|
+
extractResource(raw) {
|
|
103
|
+
return raw?.data?.object || null;
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Extract the internal orderId from a Stripe resource
|
|
108
|
+
*
|
|
109
|
+
* @param {object} resource - Raw Stripe resource (subscription, session, invoice)
|
|
110
|
+
* @returns {string|null}
|
|
111
|
+
*/
|
|
112
|
+
getOrderId(resource) {
|
|
113
|
+
return resource.metadata?.orderId || null;
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Extract the UID from a Stripe resource's metadata
|
|
118
|
+
* Used to resolve UID after fetchResource() for parity with PayPal
|
|
119
|
+
*
|
|
120
|
+
* @param {object} resource - Raw Stripe resource (subscription, session, invoice)
|
|
121
|
+
* @returns {string|null}
|
|
122
|
+
*/
|
|
123
|
+
getUid(resource) {
|
|
124
|
+
return resource.metadata?.uid || null;
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* What a Stripe refund actually moved, from Stripe's own record of the charge
|
|
129
|
+
* Returns a unified shape so transition handlers stay provider-agnostic
|
|
130
|
+
*
|
|
131
|
+
* The amounts used to be read off the webhook envelope, so a payload naming an
|
|
132
|
+
* inflated `amount_refunded` wrote that number onto the order and into the
|
|
133
|
+
* customer's refund email ([#510](https://github.com/Omega-JS-Stack/omega/issues/510)).
|
|
134
|
+
* They come from the charge Stripe answered for now: the one-time refund path
|
|
135
|
+
* already fetched it (`resourceType: 'charge'`), and the subscription path — whose
|
|
136
|
+
* fetched resource is the SUBSCRIPTION the refunded charge belongs to — reads it
|
|
137
|
+
* back by the charge id the payload names. An id is an identifier, the same trust
|
|
138
|
+
* level as the resourceId the event is looked up by; the numbers are Stripe's.
|
|
139
|
+
*
|
|
140
|
+
* Two things guard that second lookup: an envelope that names no charge at all
|
|
141
|
+
* fails PERMANENTLY before the call rather than deferring a malformed shape to
|
|
142
|
+
* the retry ladder ([#536](https://github.com/Omega-JS-Stack/omega/issues/536)),
|
|
143
|
+
* and the charge it does answer with has to link back to the subscription the
|
|
144
|
+
* event is about ([../refund-linkage.js](../refund-linkage.js)).
|
|
145
|
+
*
|
|
146
|
+
* @param {object} resource - The resource already fetched from Stripe (the record the charge must link back to)
|
|
147
|
+
* @param {object} [options] - { raw, eventType, ctx } — the envelope, for the charge id only
|
|
148
|
+
* @returns {Promise<{ amount: string|null, currency: string, reason: string|null }>}
|
|
149
|
+
*/
|
|
150
|
+
async getRefundDetails(resource, options = {}) {
|
|
151
|
+
// The charge the one-time path already fetched IS the answer, and it was
|
|
152
|
+
// fetched by the event's own resourceId — self-consistent, nothing to link
|
|
153
|
+
if (resource?.object === 'charge') {
|
|
154
|
+
return this.toRefundDetails(resource);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const chargeId = options.raw?.data?.object?.id || null;
|
|
158
|
+
|
|
159
|
+
// A refund envelope that names no charge cannot be looked up, and handing
|
|
160
|
+
// `undefined` to the SDK threw something that is not a 404 — so the #506 seam
|
|
161
|
+
// read a malformed envelope as UNREACHABLE and deferred it to the retry
|
|
162
|
+
// ladder, ten minutes at a time, until the dead-letter ceiling. Nothing about
|
|
163
|
+
// a shape like this gets better on the sixth attempt
|
|
164
|
+
// ([#536](https://github.com/Omega-JS-Stack/omega/issues/536)).
|
|
165
|
+
if (!chargeId) {
|
|
166
|
+
const failure = new Error(`stripe getRefundDetails(): ${options.eventType || 'refund event'} carries no charge id at data.object.id, so Stripe cannot be asked what came back — the envelope arrived as ${describeEnvelope(options.raw)}`);
|
|
167
|
+
|
|
168
|
+
failure.permanent = true;
|
|
169
|
+
|
|
170
|
+
throw failure;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const charge = await this.fetchResource('charge', chargeId, options);
|
|
174
|
+
|
|
175
|
+
// The charge is a SECOND record, keyed by an id the payload chose: without a
|
|
176
|
+
// link back to the subscription this event is about, an unrelated charge from
|
|
177
|
+
// the same account would have booked its refund onto this order
|
|
178
|
+
// ([#532](https://github.com/Omega-JS-Stack/omega/issues/532)). Stripe writes
|
|
179
|
+
// that link twice — the subscription the charge was made for, and the uid it
|
|
180
|
+
// was made under — and either one settles it.
|
|
181
|
+
const link = charge?.subscription
|
|
182
|
+
? { field: 'subscription', found: charge.subscription, expected: resource?.id || null }
|
|
183
|
+
: { field: 'metadata.uid', found: this.getUid(charge || {}), expected: this.getUid(resource || {}) };
|
|
184
|
+
|
|
185
|
+
assertRefundLinkage({
|
|
186
|
+
provider: 'stripe',
|
|
187
|
+
refundType: 'charge',
|
|
188
|
+
refundId: chargeId,
|
|
189
|
+
resourceType: resource?.object || 'resource',
|
|
190
|
+
resourceId: resource?.id || null,
|
|
191
|
+
ctx: options.ctx,
|
|
192
|
+
...link,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return this.toRefundDetails(charge);
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Read the refund off a charge Stripe answered with
|
|
200
|
+
*
|
|
201
|
+
* The transform half of getRefundDetails(), split out because the test provider
|
|
202
|
+
* is its own API: it holds the charge already and must never reach for Stripe's.
|
|
203
|
+
*
|
|
204
|
+
* @param {object} charge - A Stripe charge object
|
|
205
|
+
* @returns {{ amount: string|null, currency: string, reason: string|null }}
|
|
206
|
+
*/
|
|
207
|
+
toRefundDetails(charge) {
|
|
208
|
+
const amountCents = charge?.amount_refunded;
|
|
209
|
+
const latestRefund = charge?.refunds?.data?.[0];
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
amount: amountCents ? (amountCents / 100).toFixed(2) : null,
|
|
213
|
+
currency: charge?.currency?.toUpperCase() || 'USD',
|
|
214
|
+
reason: latestRefund?.reason || null,
|
|
215
|
+
};
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Transform a raw Stripe subscription object into the unified subscription shape
|
|
220
|
+
* This produces the exact same object stored in users/{uid}.subscription
|
|
221
|
+
*
|
|
222
|
+
* @param {object} rawSubscription - Raw Stripe subscription object
|
|
223
|
+
* @param {object} options
|
|
224
|
+
* @param {object} options.config - @omega.js/backend config (must contain products array)
|
|
225
|
+
* @param {string} options.eventName - Name of the webhook event (e.g., 'customer.subscription.updated')
|
|
226
|
+
* @param {string} options.eventId - ID of the webhook event (e.g., 'evt_xxx')
|
|
227
|
+
* @returns {object} Unified subscription object
|
|
228
|
+
*/
|
|
229
|
+
toUnifiedSubscription(rawSubscription, options) {
|
|
230
|
+
options = options || {};
|
|
231
|
+
const config = options.config || {};
|
|
232
|
+
|
|
233
|
+
// Resolve status
|
|
234
|
+
const status = resolveStatus(rawSubscription);
|
|
235
|
+
|
|
236
|
+
// Resolve cancellation
|
|
237
|
+
const cancellation = resolveCancellation(rawSubscription);
|
|
238
|
+
|
|
239
|
+
// Resolve trial
|
|
240
|
+
const trial = resolveTrial(rawSubscription);
|
|
241
|
+
|
|
242
|
+
// Resolve frequency
|
|
243
|
+
const frequency = resolveFrequency(rawSubscription);
|
|
244
|
+
|
|
245
|
+
// Resolve product from price
|
|
246
|
+
const product = resolveProduct(rawSubscription, config);
|
|
247
|
+
|
|
248
|
+
// Resolve expiration
|
|
249
|
+
const expires = resolveExpires(rawSubscription);
|
|
250
|
+
|
|
251
|
+
// Resolve start date
|
|
252
|
+
const startDate = resolveStartDate(rawSubscription);
|
|
253
|
+
|
|
254
|
+
// Resolve price from config
|
|
255
|
+
const price = resolvePrice(product.id, frequency, config);
|
|
256
|
+
|
|
257
|
+
// Build the unified subscription object
|
|
258
|
+
const now = powertools.timestamp(new Date(), { output: 'string' });
|
|
259
|
+
const nowUNIX = powertools.timestamp(now, { output: 'unix' });
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
product: product,
|
|
263
|
+
status: status,
|
|
264
|
+
expires: expires,
|
|
265
|
+
trial: trial,
|
|
266
|
+
cancellation: cancellation,
|
|
267
|
+
payment: {
|
|
268
|
+
provider: 'stripe',
|
|
269
|
+
orderId: rawSubscription.metadata?.orderId || null,
|
|
270
|
+
resourceId: rawSubscription.id || null,
|
|
271
|
+
frequency: frequency,
|
|
272
|
+
price: price,
|
|
273
|
+
startDate: startDate,
|
|
274
|
+
updatedBy: {
|
|
275
|
+
event: {
|
|
276
|
+
name: options.eventName || null,
|
|
277
|
+
id: options.eventId || null,
|
|
278
|
+
},
|
|
279
|
+
date: {
|
|
280
|
+
timestamp: now,
|
|
281
|
+
timestampUNIX: nowUNIX,
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Find an existing Stripe customer by uid metadata, or create one
|
|
290
|
+
*
|
|
291
|
+
* @param {string} uid - User's UID
|
|
292
|
+
* @param {string|null} email - User's email (used when creating a new customer)
|
|
293
|
+
* @param {object} ctx - Assistant instance for logging
|
|
294
|
+
* @returns {object} Stripe customer object
|
|
295
|
+
*/
|
|
296
|
+
async resolveCustomer(uid, email, ctx) {
|
|
297
|
+
const stripe = this.init();
|
|
298
|
+
|
|
299
|
+
// Search for existing customer with this uid
|
|
300
|
+
const search = await stripe.customers.search({
|
|
301
|
+
query: `metadata['uid']:'${uid}'`,
|
|
302
|
+
limit: 1,
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
if (search.data.length > 0) {
|
|
306
|
+
const existing = search.data[0];
|
|
307
|
+
ctx.log(`Found existing Stripe customer: ${existing.id}`);
|
|
308
|
+
return existing;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Create new customer
|
|
312
|
+
// Use an idempotency key scoped to the uid so concurrent creates (e.g. user
|
|
313
|
+
// double-clicks checkout) return the same customer instead of duplicates.
|
|
314
|
+
// Stripe caches the response under this key for 24 hours.
|
|
315
|
+
const params = {
|
|
316
|
+
metadata: { uid },
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
if (email) {
|
|
320
|
+
params.email = email;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const customer = await stripe.customers.create(params, {
|
|
324
|
+
idempotencyKey: `backend-customer-create-${uid}`,
|
|
325
|
+
});
|
|
326
|
+
ctx.log(`Created new Stripe customer: ${customer.id}`);
|
|
327
|
+
return customer;
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Resolve the Stripe price ID by fetching active prices from the Stripe product
|
|
332
|
+
* and matching by interval + amount.
|
|
333
|
+
*
|
|
334
|
+
* @param {object} product - Product object from config (must have .prices and .stripe.productId)
|
|
335
|
+
* @param {string} productType - 'subscription' or 'one-time'
|
|
336
|
+
* @param {string} frequency - 'monthly', 'annually', etc. (subscriptions) — ignored for one-time
|
|
337
|
+
* @returns {Promise<string>} Stripe price ID
|
|
338
|
+
* @throws {Error} If product is archived, missing Stripe product ID, or no matching price found
|
|
339
|
+
*/
|
|
340
|
+
async resolvePriceId(product, productType, frequency) {
|
|
341
|
+
if (product.archived) {
|
|
342
|
+
throw new Error(`Product ${product.id} is archived`);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const stripeProductId = product.stripe?.productId;
|
|
346
|
+
|
|
347
|
+
if (!stripeProductId) {
|
|
348
|
+
throw new Error(`No Stripe product ID for ${product.id}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const key = productType === 'subscription' ? frequency : 'once';
|
|
352
|
+
const expectedAmount = product.prices?.[key];
|
|
353
|
+
|
|
354
|
+
if (!expectedAmount) {
|
|
355
|
+
throw new Error(`No price configured for ${product.id}/${key}`);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const amountCents = Math.round(expectedAmount * 100);
|
|
359
|
+
|
|
360
|
+
// Fetch active prices from Stripe for this product
|
|
361
|
+
const stripe = this.init();
|
|
362
|
+
|
|
363
|
+
const prices = [];
|
|
364
|
+
for await (const price of stripe.prices.list({ product: stripeProductId, active: true, limit: 100 })) {
|
|
365
|
+
prices.push(price);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Match by interval + amount
|
|
369
|
+
if (productType === 'subscription') {
|
|
370
|
+
const interval = FREQUENCY_TO_INTERVAL[frequency] || 'month';
|
|
371
|
+
const match = prices.find(p =>
|
|
372
|
+
p.recurring?.interval === interval
|
|
373
|
+
&& p.unit_amount === amountCents
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
if (!match) {
|
|
377
|
+
throw new Error(`No active Stripe price for ${product.id}/${frequency} at $${expectedAmount} (product: ${stripeProductId})`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return match.id;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// One-time: match by amount, no recurring
|
|
384
|
+
const match = prices.find(p => !p.recurring && p.unit_amount === amountCents);
|
|
385
|
+
|
|
386
|
+
if (!match) {
|
|
387
|
+
throw new Error(`No active Stripe price for ${product.id}/once at $${expectedAmount} (product: ${stripeProductId})`);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return match.id;
|
|
391
|
+
},
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Resolve or create a Stripe coupon for a discount
|
|
395
|
+
* Uses a deterministic ID so the same discount always maps to the same coupon
|
|
396
|
+
*
|
|
397
|
+
* Stripe coupons come in two shapes and a discount is one or the other:
|
|
398
|
+
* `percent_off`, or `amount_off` in the currency's MINOR unit (cents) with a
|
|
399
|
+
* `currency` beside it — Stripe rejects an amount coupon without one. The two
|
|
400
|
+
* shapes carry different ids so a code can never collide with the other form,
|
|
401
|
+
* and the `_ONCE` ids are byte-identical to what they have always been, so
|
|
402
|
+
* coupons already live in a brand's account keep resolving instead of
|
|
403
|
+
* duplicating under a new id
|
|
404
|
+
* ([#239](https://github.com/Omega-JS-Stack/omega/issues/239)).
|
|
405
|
+
*
|
|
406
|
+
* TWO callers now: the checkout's discount codes and the cancel flow's save
|
|
407
|
+
* offer ([#268](https://github.com/Omega-JS-Stack/omega/issues/268)), which is
|
|
408
|
+
* also the only reason `duration` is read off the discount rather than fixed —
|
|
409
|
+
* an offer a brand configured as `forever` is a permanent price cut and gets
|
|
410
|
+
* its own coupon, never the one-cycle one.
|
|
411
|
+
*
|
|
412
|
+
* Verified against the params the SDK is asked to create, not against Stripe:
|
|
413
|
+
* live-provider verification is a Stage 3 item, the same trust level as the
|
|
414
|
+
* rest of this library ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)).
|
|
415
|
+
*
|
|
416
|
+
* @param {object} discount - A discount-codes validate() result (or the save offer as one)
|
|
417
|
+
* @param {object} ctx - Assistant instance for logging + the brand's currency
|
|
418
|
+
* @returns {Promise<string>} The Stripe coupon id
|
|
419
|
+
*/
|
|
420
|
+
async resolveCoupon(discount, ctx) {
|
|
421
|
+
const stripe = this.init();
|
|
422
|
+
|
|
423
|
+
const isAmount = discount.amount > 0;
|
|
424
|
+
const duration = discount.duration || 'once';
|
|
425
|
+
const currency = ctx.Manager?.config?.payment?.currency || 'USD';
|
|
426
|
+
const scope = duration.toUpperCase();
|
|
427
|
+
const appliesTo = duration === 'once' ? 'first payment' : 'every payment';
|
|
428
|
+
const couponId = isAmount
|
|
429
|
+
? `BEM_${discount.code}_${discount.amount}AMTOFF_${scope}`
|
|
430
|
+
: `BEM_${discount.code}_${discount.percent}OFF_${scope}`;
|
|
431
|
+
|
|
432
|
+
try {
|
|
433
|
+
// Check if coupon already exists
|
|
434
|
+
await stripe.coupons.retrieve(couponId);
|
|
435
|
+
ctx.log(`Stripe coupon exists: ${couponId}`);
|
|
436
|
+
return couponId;
|
|
437
|
+
} catch (e) {
|
|
438
|
+
if (e.code !== 'resource_missing') {
|
|
439
|
+
throw e;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Create the coupon
|
|
444
|
+
// Idempotency key uses the deterministic couponId so concurrent requests for
|
|
445
|
+
// the same discount don't race each other into a duplicate-create error.
|
|
446
|
+
// Stripe returns the cached response for 24 hours.
|
|
447
|
+
await stripe.coupons.create({
|
|
448
|
+
id: couponId,
|
|
449
|
+
duration: duration,
|
|
450
|
+
...(isAmount
|
|
451
|
+
? {
|
|
452
|
+
amount_off: Math.round(discount.amount * 100),
|
|
453
|
+
currency: currency.toLowerCase(),
|
|
454
|
+
name: `${discount.code} (${discount.amount.toFixed(2)} ${currency.toUpperCase()} off ${appliesTo})`,
|
|
455
|
+
}
|
|
456
|
+
: {
|
|
457
|
+
percent_off: discount.percent,
|
|
458
|
+
name: `${discount.code} (${discount.percent}% off ${appliesTo})`,
|
|
459
|
+
}),
|
|
460
|
+
}, {
|
|
461
|
+
idempotencyKey: `backend-coupon-${couponId}`,
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
ctx.log(`Stripe coupon created: ${couponId}`);
|
|
465
|
+
return couponId;
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Transform a raw Stripe one-time payment resource into a unified shape
|
|
470
|
+
* Mirrors subscription structure: { product, status, payment: { ... } }
|
|
471
|
+
*
|
|
472
|
+
* @param {object} rawResource - Raw Stripe resource (session, invoice, etc.)
|
|
473
|
+
* @param {object} options
|
|
474
|
+
* @returns {object} Unified one-time payment object
|
|
475
|
+
*/
|
|
476
|
+
toUnifiedOneTime(rawResource, options) {
|
|
477
|
+
options = options || {};
|
|
478
|
+
const config = options.config || {};
|
|
479
|
+
|
|
480
|
+
const now = powertools.timestamp(new Date(), { output: 'string' });
|
|
481
|
+
const nowUNIX = powertools.timestamp(now, { output: 'unix' });
|
|
482
|
+
|
|
483
|
+
// Resolve product + price from config
|
|
484
|
+
const productId = rawResource.metadata?.productId;
|
|
485
|
+
const product = resolveProductOneTime(productId, config);
|
|
486
|
+
const price = resolvePrice(productId, 'once', config);
|
|
487
|
+
|
|
488
|
+
return {
|
|
489
|
+
product: product,
|
|
490
|
+
status: rawResource.status === 'complete' ? 'completed' : rawResource.status || 'unknown',
|
|
491
|
+
payment: {
|
|
492
|
+
provider: 'stripe',
|
|
493
|
+
orderId: rawResource.metadata?.orderId || null,
|
|
494
|
+
resourceId: rawResource.id || null,
|
|
495
|
+
price: price,
|
|
496
|
+
updatedBy: {
|
|
497
|
+
event: {
|
|
498
|
+
name: options.eventName || null,
|
|
499
|
+
id: options.eventId || null,
|
|
500
|
+
},
|
|
501
|
+
date: {
|
|
502
|
+
timestamp: now,
|
|
503
|
+
timestampUNIX: nowUNIX,
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
};
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Say what a webhook envelope actually looked like
|
|
513
|
+
*
|
|
514
|
+
* A malformed envelope is a programmer/parser error, and the only thing that makes
|
|
515
|
+
* one debuggable is knowing what arrived instead of what was expected: the event
|
|
516
|
+
* type, and the keys the object it carried DID have
|
|
517
|
+
* ([#536](https://github.com/Omega-JS-Stack/omega/issues/536)).
|
|
518
|
+
*
|
|
519
|
+
* @param {object|null} raw - The raw Stripe webhook payload
|
|
520
|
+
* @returns {string}
|
|
521
|
+
*/
|
|
522
|
+
function describeEnvelope(raw) {
|
|
523
|
+
const object = raw?.data?.object;
|
|
524
|
+
|
|
525
|
+
if (!object || typeof object !== 'object') {
|
|
526
|
+
return `type=${raw?.type || 'unknown'}, data.object=${object === undefined ? 'absent' : JSON.stringify(object)}`;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return `type=${raw?.type || 'unknown'}, data.object.object=${object.object || 'unnamed'}, data.object keys=[${Object.keys(object).join(', ')}]`;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Map Stripe subscription status to unified status
|
|
534
|
+
*
|
|
535
|
+
* | Stripe Status | Unified Status |
|
|
536
|
+
* |----------------------|----------------|
|
|
537
|
+
* | active | active |
|
|
538
|
+
* | trialing | active |
|
|
539
|
+
* | past_due | suspended |
|
|
540
|
+
* | unpaid | suspended |
|
|
541
|
+
* | canceled | cancelled |
|
|
542
|
+
* | incomplete | cancelled |
|
|
543
|
+
* | incomplete_expired | cancelled |
|
|
544
|
+
*/
|
|
545
|
+
function resolveStatus(raw) {
|
|
546
|
+
const stripeStatus = raw.status;
|
|
547
|
+
|
|
548
|
+
if (stripeStatus === 'active' || stripeStatus === 'trialing') {
|
|
549
|
+
return 'active';
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (stripeStatus === 'past_due' || stripeStatus === 'unpaid') {
|
|
553
|
+
return 'suspended';
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// canceled, incomplete, incomplete_expired, or anything else
|
|
557
|
+
return 'cancelled';
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Resolve cancellation state from Stripe subscription
|
|
562
|
+
* Handles cancel_at_period_end for pending cancellations
|
|
563
|
+
*/
|
|
564
|
+
function resolveCancellation(raw) {
|
|
565
|
+
// Pending cancellation: active but set to cancel at period end
|
|
566
|
+
if (raw.cancel_at_period_end) {
|
|
567
|
+
const periodEnd = raw.current_period_end || raw.items?.data?.[0]?.current_period_end || 0;
|
|
568
|
+
const cancelAt = raw.cancel_at
|
|
569
|
+
? powertools.timestamp(new Date(raw.cancel_at * 1000), { output: 'string' })
|
|
570
|
+
: powertools.timestamp(new Date(periodEnd * 1000), { output: 'string' });
|
|
571
|
+
|
|
572
|
+
return {
|
|
573
|
+
pending: true,
|
|
574
|
+
date: {
|
|
575
|
+
timestamp: cancelAt,
|
|
576
|
+
timestampUNIX: powertools.timestamp(cancelAt, { output: 'unix' }),
|
|
577
|
+
},
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Already cancelled
|
|
582
|
+
if (raw.canceled_at) {
|
|
583
|
+
const cancelledDate = powertools.timestamp(new Date(raw.canceled_at * 1000), { output: 'string' });
|
|
584
|
+
|
|
585
|
+
return {
|
|
586
|
+
pending: false,
|
|
587
|
+
date: {
|
|
588
|
+
timestamp: cancelledDate,
|
|
589
|
+
timestampUNIX: powertools.timestamp(cancelledDate, { output: 'unix' }),
|
|
590
|
+
},
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// No cancellation
|
|
595
|
+
return {
|
|
596
|
+
pending: false,
|
|
597
|
+
date: {
|
|
598
|
+
timestamp: EPOCH_ZERO,
|
|
599
|
+
timestampUNIX: EPOCH_ZERO_UNIX,
|
|
600
|
+
},
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Resolve trial state from Stripe subscription
|
|
606
|
+
*/
|
|
607
|
+
function resolveTrial(raw) {
|
|
608
|
+
const trialStart = raw.trial_start ? raw.trial_start * 1000 : 0;
|
|
609
|
+
const trialEnd = raw.trial_end ? raw.trial_end * 1000 : 0;
|
|
610
|
+
const activated = !!(trialStart && trialEnd);
|
|
611
|
+
|
|
612
|
+
// Build trial expiration
|
|
613
|
+
let trialExpires = { timestamp: EPOCH_ZERO, timestampUNIX: EPOCH_ZERO_UNIX };
|
|
614
|
+
if (trialEnd) {
|
|
615
|
+
const trialEndDate = powertools.timestamp(new Date(trialEnd), { output: 'string' });
|
|
616
|
+
trialExpires = {
|
|
617
|
+
timestamp: trialEndDate,
|
|
618
|
+
timestampUNIX: powertools.timestamp(trialEndDate, { output: 'unix' }),
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return {
|
|
623
|
+
claimed: activated,
|
|
624
|
+
expires: trialExpires,
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Resolve billing frequency from Stripe subscription
|
|
630
|
+
*/
|
|
631
|
+
function resolveFrequency(raw) {
|
|
632
|
+
// Stripe stores interval on the plan/price object
|
|
633
|
+
const interval = raw.plan?.interval
|
|
634
|
+
|| raw.items?.data?.[0]?.price?.recurring?.interval
|
|
635
|
+
|| null;
|
|
636
|
+
|
|
637
|
+
return INTERVAL_TO_FREQUENCY[interval] || null;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Resolve product by matching the Stripe product ID against config products
|
|
642
|
+
* Returns { id, name } — falls back to basic if no match is found
|
|
643
|
+
*/
|
|
644
|
+
function resolveProduct(raw, config) {
|
|
645
|
+
// Get the Stripe product ID from the subscription
|
|
646
|
+
const stripeProductId = raw.items?.data?.[0]?.price?.product
|
|
647
|
+
|| raw.plan?.product
|
|
648
|
+
|| null;
|
|
649
|
+
|
|
650
|
+
if (!stripeProductId || !config.payment?.products) {
|
|
651
|
+
return { id: 'basic', name: 'Basic' };
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Test-mode sentinel: the test provider synthesizes "_test_<id>" when no real
|
|
655
|
+
// Stripe product is configured. Map it back to the matching @omega.js/backend product so the
|
|
656
|
+
// pipeline can be exercised end-to-end without real Stripe credentials.
|
|
657
|
+
if (typeof stripeProductId === 'string' && stripeProductId.startsWith('_test_')) {
|
|
658
|
+
const bemId = stripeProductId.slice('_test_'.length);
|
|
659
|
+
const product = config.payment.products.find((p) => p.id === bemId);
|
|
660
|
+
if (product) {
|
|
661
|
+
return { id: product.id, name: product.name || product.id };
|
|
662
|
+
}
|
|
663
|
+
return { id: 'basic', name: 'Basic' };
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
for (const product of config.payment.products) {
|
|
667
|
+
// Match current product ID
|
|
668
|
+
if (product.stripe?.productId === stripeProductId) {
|
|
669
|
+
return { id: product.id, name: product.name || product.id };
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Match legacy product IDs (pre-migration Stripe products)
|
|
673
|
+
if (product.stripe?.legacyProductIds?.includes(stripeProductId)) {
|
|
674
|
+
return { id: product.id, name: product.name || product.id };
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// No match found
|
|
679
|
+
return { id: 'basic', name: 'Basic' };
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Resolve product for one-time payments by matching productId from metadata
|
|
684
|
+
* Returns { id, name } — falls back to 'unknown' if no match is found
|
|
685
|
+
*/
|
|
686
|
+
function resolveProductOneTime(productId, config) {
|
|
687
|
+
if (!productId || !config.payment?.products) {
|
|
688
|
+
return { id: productId || 'unknown', name: 'Unknown' };
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
const product = config.payment.products.find(p => p.id === productId);
|
|
692
|
+
|
|
693
|
+
if (!product) {
|
|
694
|
+
return { id: productId, name: productId };
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return { id: product.id, name: product.name || product.id };
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Resolve subscription expiration from Stripe data
|
|
702
|
+
*/
|
|
703
|
+
function resolveExpires(raw) {
|
|
704
|
+
// Stripe API 2025+ moves period dates to items.data[0]
|
|
705
|
+
const periodEndRaw = raw.current_period_end
|
|
706
|
+
|| raw.items?.data?.[0]?.current_period_end
|
|
707
|
+
|| 0;
|
|
708
|
+
|
|
709
|
+
const periodEnd = periodEndRaw
|
|
710
|
+
? powertools.timestamp(new Date(periodEndRaw * 1000), { output: 'string' })
|
|
711
|
+
: EPOCH_ZERO;
|
|
712
|
+
|
|
713
|
+
return {
|
|
714
|
+
timestamp: periodEnd,
|
|
715
|
+
timestampUNIX: periodEnd !== EPOCH_ZERO
|
|
716
|
+
? powertools.timestamp(periodEnd, { output: 'unix' })
|
|
717
|
+
: EPOCH_ZERO_UNIX,
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Resolve subscription start date from Stripe data
|
|
723
|
+
*/
|
|
724
|
+
function resolveStartDate(raw) {
|
|
725
|
+
const startDate = raw.start_date
|
|
726
|
+
? powertools.timestamp(new Date(raw.start_date * 1000), { output: 'string' })
|
|
727
|
+
: EPOCH_ZERO;
|
|
728
|
+
|
|
729
|
+
return {
|
|
730
|
+
timestamp: startDate,
|
|
731
|
+
timestampUNIX: startDate !== EPOCH_ZERO
|
|
732
|
+
? powertools.timestamp(startDate, { output: 'unix' })
|
|
733
|
+
: EPOCH_ZERO_UNIX,
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Resolve the display price for a product/frequency from config
|
|
739
|
+
*
|
|
740
|
+
* @param {string} productId - Product ID (e.g., 'premium')
|
|
741
|
+
* @param {string} frequency - 'monthly', 'annually', or 'once'
|
|
742
|
+
* @param {object} config - App config
|
|
743
|
+
* @returns {number} Price amount (e.g., 4.99) or 0
|
|
744
|
+
*/
|
|
745
|
+
function resolvePrice(productId, frequency, config) {
|
|
746
|
+
const product = config.payment?.products?.find(p => p.id === productId);
|
|
747
|
+
|
|
748
|
+
if (!product || !product.prices) {
|
|
749
|
+
return 0;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return product.prices[frequency] || 0;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
module.exports = Stripe;
|