@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,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push notification library — send FCM notifications to subscribers
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* const notification = require('./libraries/notification.js');
|
|
6
|
+
* await notification.send(ctx, { title, body, icon, clickAction, filters });
|
|
7
|
+
*
|
|
8
|
+
* Used by:
|
|
9
|
+
* - POST /admin/notification route
|
|
10
|
+
* - marketing-campaigns cron job (type: 'push')
|
|
11
|
+
*/
|
|
12
|
+
const PATH_NOTIFICATIONS = 'notifications';
|
|
13
|
+
const BAD_TOKEN_REASONS = [
|
|
14
|
+
'messaging/invalid-registration-token',
|
|
15
|
+
'messaging/registration-token-not-registered',
|
|
16
|
+
];
|
|
17
|
+
const BATCH_SIZE = 500;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Send push notification to FCM subscribers.
|
|
21
|
+
*
|
|
22
|
+
* @param {object} ctx - @omega.js/backend ctx instance
|
|
23
|
+
* @param {object} options
|
|
24
|
+
* @param {string} options.title - Notification title
|
|
25
|
+
* @param {string} options.body - Notification body
|
|
26
|
+
* @param {string} [options.icon] - Notification icon URL (defaults to brand.images.brandmark)
|
|
27
|
+
* @param {string} [options.clickAction] - URL to open on click (defaults to brand.url)
|
|
28
|
+
* @param {object} [options.filters] - Targeting filters
|
|
29
|
+
* @param {Array<string>} [options.filters.tags] - Filter by tags
|
|
30
|
+
* @param {string} [options.filters.owner] - Filter by owner UID
|
|
31
|
+
* @param {string} [options.filters.token] - Send to specific token
|
|
32
|
+
* @param {number} [options.filters.limit] - Max tokens to send to
|
|
33
|
+
* @returns {{ subscribers: number, batches: number, sent: number, deleted: number }}
|
|
34
|
+
*/
|
|
35
|
+
async function send(ctx, options) {
|
|
36
|
+
const { title, body, icon, clickAction, filters } = options;
|
|
37
|
+
|
|
38
|
+
if (!title || !body) {
|
|
39
|
+
throw new Error('Notification title and body are required');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const notification = buildPayload(ctx.Manager.config?.brand, { title, body, icon, clickAction });
|
|
43
|
+
|
|
44
|
+
ctx.log('notification.send():', notification);
|
|
45
|
+
|
|
46
|
+
const response = { subscribers: 0, batches: 0, sent: 0, deleted: 0 };
|
|
47
|
+
const filterOptions = {
|
|
48
|
+
tags: filters?.tags || false,
|
|
49
|
+
owner: filters?.owner || null,
|
|
50
|
+
token: filters?.token || null,
|
|
51
|
+
limit: filters?.limit || null,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
await processTokens(ctx, notification, filterOptions, response);
|
|
55
|
+
|
|
56
|
+
return response;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Build the FCM payload from the caller's options and the brand's OWN config.
|
|
61
|
+
*
|
|
62
|
+
* A push notification lands on a user's lock screen wearing whoever's icon and
|
|
63
|
+
* link it carries, so there is no framework fallback for either. The icon comes
|
|
64
|
+
* from `brand.images.brandmark` and is OMITTED when unconfigured (a text-only
|
|
65
|
+
* notification, never another company's mark); the click target comes from
|
|
66
|
+
* `brand.url` and fails LOUDLY when unconfigured, because a push with nowhere
|
|
67
|
+
* to go is not worth sending anywhere else.
|
|
68
|
+
*
|
|
69
|
+
* @param {object} brand - Resolved brand config object
|
|
70
|
+
* @param {object} options
|
|
71
|
+
* @param {string} options.title
|
|
72
|
+
* @param {string} options.body
|
|
73
|
+
* @param {string} [options.icon] - Explicit icon URL (wins over config)
|
|
74
|
+
* @param {string} [options.clickAction] - Explicit click target (wins over config)
|
|
75
|
+
* @returns {{ title: string, body: string, imageUrl?: string, click_action: string }}
|
|
76
|
+
* @throws {Error} When no click target is configured, or it is not a valid URL
|
|
77
|
+
*/
|
|
78
|
+
function buildPayload(brand, { title, body, icon, clickAction }) {
|
|
79
|
+
const imageUrl = icon || brand?.images?.brandmark;
|
|
80
|
+
const clickTarget = clickAction || brand?.url;
|
|
81
|
+
|
|
82
|
+
if (!clickTarget) {
|
|
83
|
+
// Coded 400 like the email library's config-hole throws — a code-less Error
|
|
84
|
+
// would respond as a 500 and capture to Sentry for what is a brand-config fault.
|
|
85
|
+
const err = new Error('Missing brand.url in config/omega.json5 — required to send a push notification (or pass clickAction)');
|
|
86
|
+
err.code = 400;
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const notification = { title, body, click_action: clickTarget };
|
|
91
|
+
|
|
92
|
+
if (imageUrl) {
|
|
93
|
+
notification.imageUrl = imageUrl;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Add cache buster to click_action URL
|
|
97
|
+
try {
|
|
98
|
+
const url = new URL(notification.click_action);
|
|
99
|
+
url.searchParams.set('cb', new Date().getTime());
|
|
100
|
+
notification.click_action = url.toString();
|
|
101
|
+
} catch (e) {
|
|
102
|
+
throw new Error(`Invalid click_action URL: ${e.message}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return notification;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function processTokens(ctx, notification, options, response) {
|
|
109
|
+
const Manager = ctx.Manager;
|
|
110
|
+
|
|
111
|
+
// Specific token — send directly
|
|
112
|
+
if (options.token) {
|
|
113
|
+
ctx.log(`Sending to specific token: ${options.token}`);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
await sendBatch(ctx, [options.token], 0, notification, response);
|
|
117
|
+
} catch (e) {
|
|
118
|
+
ctx.error('Error sending to specific token', e);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Build query conditions
|
|
125
|
+
const queryConditions = [];
|
|
126
|
+
|
|
127
|
+
if (options.tags) {
|
|
128
|
+
queryConditions.push({ field: 'tags', operator: 'array-contains-any', value: options.tags });
|
|
129
|
+
}
|
|
130
|
+
if (options.owner) {
|
|
131
|
+
queryConditions.push({ field: 'owner', operator: '==', value: options.owner });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const maxBatches = options.limit
|
|
135
|
+
? Math.ceil(options.limit / BATCH_SIZE)
|
|
136
|
+
: Infinity;
|
|
137
|
+
|
|
138
|
+
ctx.log('Processing tokens with filters:', {
|
|
139
|
+
tags: options.tags,
|
|
140
|
+
owner: options.owner,
|
|
141
|
+
limit: options.limit,
|
|
142
|
+
maxBatches,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
let tokensProcessed = 0;
|
|
146
|
+
|
|
147
|
+
await Manager.Utilities().iterateCollection(
|
|
148
|
+
async (batch, index) => {
|
|
149
|
+
const batchTokens = [];
|
|
150
|
+
|
|
151
|
+
for (const doc of batch.docs) {
|
|
152
|
+
if (options.limit && tokensProcessed >= options.limit) {
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const data = doc.data();
|
|
157
|
+
batchTokens.push(data.token);
|
|
158
|
+
tokensProcessed++;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (batchTokens.length === 0) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
ctx.log(`Sending batch ${index} with ${batchTokens.length} tokens.`);
|
|
167
|
+
await sendBatch(ctx, batchTokens, index, notification, response);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
ctx.error(`Error sending batch ${index}`, e);
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
collection: PATH_NOTIFICATIONS,
|
|
174
|
+
where: queryConditions,
|
|
175
|
+
batchSize: BATCH_SIZE,
|
|
176
|
+
maxBatches,
|
|
177
|
+
log: true,
|
|
178
|
+
}
|
|
179
|
+
).catch(e => {
|
|
180
|
+
ctx.error(`Error during token processing: ${e}`);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function sendBatch(ctx, batch, id, notification, response) {
|
|
185
|
+
const { admin } = ctx.Manager.libraries;
|
|
186
|
+
|
|
187
|
+
ctx.log(`Sending batch #${id}: tokens=${batch.length}...`);
|
|
188
|
+
|
|
189
|
+
const messages = batch.map(token => ({
|
|
190
|
+
token,
|
|
191
|
+
notification: {
|
|
192
|
+
title: notification.title,
|
|
193
|
+
body: notification.body,
|
|
194
|
+
...(notification.imageUrl ? { imageUrl: notification.imageUrl } : {}),
|
|
195
|
+
},
|
|
196
|
+
webpush: {
|
|
197
|
+
notification: {
|
|
198
|
+
title: notification.title,
|
|
199
|
+
body: notification.body,
|
|
200
|
+
...(notification.imageUrl ? { icon: notification.imageUrl } : {}),
|
|
201
|
+
click_action: notification.click_action,
|
|
202
|
+
},
|
|
203
|
+
data: {
|
|
204
|
+
click_action: notification.click_action,
|
|
205
|
+
},
|
|
206
|
+
fcm_options: {
|
|
207
|
+
link: notification.click_action,
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
data: {
|
|
211
|
+
click_action: notification.click_action,
|
|
212
|
+
},
|
|
213
|
+
}));
|
|
214
|
+
|
|
215
|
+
const result = await admin.messaging().sendEach(messages);
|
|
216
|
+
|
|
217
|
+
ctx.log(`Sent batch #${id}: success=${result.successCount}, failures=${result.failureCount}`);
|
|
218
|
+
|
|
219
|
+
result.responses = result.responses.map((item, index) => {
|
|
220
|
+
item.token = batch[index];
|
|
221
|
+
return item;
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Clean bad tokens
|
|
225
|
+
if (result.failureCount > 0) {
|
|
226
|
+
await cleanTokens(ctx, batch, result.responses, id, response);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
response.sent += (batch.length - result.failureCount);
|
|
230
|
+
response.batches++;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function cleanTokens(ctx, batch, results, id, response) {
|
|
234
|
+
const { admin } = ctx.Manager.libraries;
|
|
235
|
+
|
|
236
|
+
const cleanPromises = results
|
|
237
|
+
.map((item) => {
|
|
238
|
+
if (!item.error || !BAD_TOKEN_REASONS.includes(item?.error?.code)) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return admin.firestore().doc(`${PATH_NOTIFICATIONS}/${item.token}`).delete()
|
|
243
|
+
.then(() => {
|
|
244
|
+
ctx.log(`Deleted bad token: ${item.token} (${item.error.code})`);
|
|
245
|
+
response.deleted++;
|
|
246
|
+
})
|
|
247
|
+
.catch((e) => {
|
|
248
|
+
ctx.error(`Failed to delete bad token: ${item.token}`, e);
|
|
249
|
+
});
|
|
250
|
+
})
|
|
251
|
+
.filter(Boolean);
|
|
252
|
+
|
|
253
|
+
await Promise.all(cleanPromises);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = { send, buildPayload };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compatibility shim — `libraries/openai.js` was the original AI library.
|
|
3
|
+
* It has been moved to `libraries/ai/providers/openai.js` and the new unified
|
|
4
|
+
* surface is `libraries/ai/index.js`.
|
|
5
|
+
*
|
|
6
|
+
* Existing callers (`require('./libraries/openai.js')`) continue to receive the
|
|
7
|
+
* OpenAI provider class with the same constructor + prototype as before. New
|
|
8
|
+
* code should use the unified surface:
|
|
9
|
+
*
|
|
10
|
+
* const ai = Manager.AI(ctx);
|
|
11
|
+
* await ai.request({ provider: 'openai' | 'anthropic', ... });
|
|
12
|
+
*/
|
|
13
|
+
module.exports = require('./ai/providers/openai.js');
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discount codes — SSOT for all promo codes
|
|
3
|
+
*
|
|
4
|
+
* Each code maps to a discount definition. A code is EITHER percent-based or
|
|
5
|
+
* amount-based — the two shapes Stripe's coupons come in:
|
|
6
|
+
* - percent: Percentage off (1-100) — Stripe's `percent_off`
|
|
7
|
+
* - amount: Flat dollars off — Stripe's `amount_off` (which is CENTS on
|
|
8
|
+
* Stripe's side; every builder converts)
|
|
9
|
+
* - duration: 'once' (first payment only)
|
|
10
|
+
* - eligible: Optional function (user) => boolean. If present, the code is only
|
|
11
|
+
* valid for users who pass this check. Receives the raw user doc or User instance.
|
|
12
|
+
* If omitted, the code is valid for everyone.
|
|
13
|
+
*/
|
|
14
|
+
const User = require('../../helpers/user.js');
|
|
15
|
+
|
|
16
|
+
const DISCOUNT_CODES = {
|
|
17
|
+
// Website (displayed on pricing page, landing pages — no eligibility restrictions)
|
|
18
|
+
'WELCOME15': { percent: 15, duration: 'once' },
|
|
19
|
+
'SAVE10': { percent: 10, duration: 'once' },
|
|
20
|
+
'FLASH20': { percent: 20, duration: 'once' },
|
|
21
|
+
'GIFT15': { percent: 15, duration: 'once' },
|
|
22
|
+
'WELCOME10OFF': { amount: 10, duration: 'once' },
|
|
23
|
+
|
|
24
|
+
// Email campaigns (used by recurring sale seeds — restricted by audience)
|
|
25
|
+
'UPGRADE15': {
|
|
26
|
+
percent: 15,
|
|
27
|
+
duration: 'once',
|
|
28
|
+
eligible: (user) => {
|
|
29
|
+
const sub = User.resolveSubscription(user);
|
|
30
|
+
return sub.plan === 'basic';
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
'COMEBACK20': {
|
|
34
|
+
percent: 20,
|
|
35
|
+
duration: 'once',
|
|
36
|
+
eligible: (user) => {
|
|
37
|
+
const sub = User.resolveSubscription(user);
|
|
38
|
+
return sub.plan === 'basic' && user.subscription?.trial?.claimed === true;
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
'MISSYOU25': {
|
|
42
|
+
percent: 25,
|
|
43
|
+
duration: 'once',
|
|
44
|
+
eligible: (user) => {
|
|
45
|
+
const sub = User.resolveSubscription(user);
|
|
46
|
+
return sub.everPaid && user.subscription?.status === 'cancelled';
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
'TRYAGAIN10': {
|
|
50
|
+
percent: 10,
|
|
51
|
+
duration: 'once',
|
|
52
|
+
eligible: (user) => {
|
|
53
|
+
return user.subscription?.status === 'cancelled';
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Validate a discount code, optionally checking user eligibility.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} code - The discount code (case-insensitive)
|
|
62
|
+
* @param {object} [user] - User doc or User instance. If provided and the code has
|
|
63
|
+
* an eligible() function, eligibility is checked. If not provided, eligibility is skipped.
|
|
64
|
+
* @returns {{ valid: boolean, code: string, percent?: number, amount?: number, duration?: string, reason?: string }}
|
|
65
|
+
*/
|
|
66
|
+
function validate(code, user) {
|
|
67
|
+
const normalized = (code || '').trim().toUpperCase();
|
|
68
|
+
|
|
69
|
+
if (!normalized) {
|
|
70
|
+
return { valid: false, code: normalized };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const entry = DISCOUNT_CODES[normalized];
|
|
74
|
+
|
|
75
|
+
if (!entry) {
|
|
76
|
+
return { valid: false, code: normalized };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check eligibility if user is provided and code has a restriction
|
|
80
|
+
if (user && entry.eligible) {
|
|
81
|
+
// Support both raw user doc and User instance (check .properties for User instance)
|
|
82
|
+
const userDoc = user.properties || user;
|
|
83
|
+
|
|
84
|
+
if (!entry.eligible(userDoc)) {
|
|
85
|
+
return { valid: false, code: normalized, reason: 'not eligible' };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// The result carries the ONE shape the code has — everything downstream reads a
|
|
90
|
+
// validate() RESULT and never the table, so an amount code that reported no
|
|
91
|
+
// amount would quietly charge full price everywhere. The absent shape is
|
|
92
|
+
// OMITTED, never set to undefined: `POST /payments/intent` writes this object
|
|
93
|
+
// into payments-intents/{orderId}, and firebase-admin refuses a document
|
|
94
|
+
// carrying an undefined value — synchronously, after the provider has already
|
|
95
|
+
// created the real checkout session
|
|
96
|
+
// ([#239](https://github.com/Omega-JS-Stack/omega/issues/239)).
|
|
97
|
+
return {
|
|
98
|
+
valid: true,
|
|
99
|
+
code: normalized,
|
|
100
|
+
...(entry.percent !== undefined && { percent: entry.percent }),
|
|
101
|
+
...(entry.amount !== undefined && { amount: entry.amount }),
|
|
102
|
+
duration: entry.duration,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Which shape a discount can be QUOTED as, or null for neither.
|
|
108
|
+
*
|
|
109
|
+
* A code in the table always declares exactly one shape, so a fresh validate()
|
|
110
|
+
* result always answers 'percent' or 'amount' — the providers branch on that
|
|
111
|
+
* directly. A discount read back off a STORED order is the case this exists for:
|
|
112
|
+
* one written before the amount field existed is `valid` and carries no shape at
|
|
113
|
+
* all, and a reader that assumed one would throw on it
|
|
114
|
+
* ([#239](https://github.com/Omega-JS-Stack/omega/issues/239)).
|
|
115
|
+
*
|
|
116
|
+
* @param {object} [discount] - A validate() result, a stored order's discount, or null
|
|
117
|
+
* @returns {'percent'|'amount'|null}
|
|
118
|
+
*/
|
|
119
|
+
function promoShape(discount) {
|
|
120
|
+
if (discount?.valid !== true) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (discount.percent > 0) {
|
|
125
|
+
return 'percent';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return discount.amount > 0 ? 'amount' : null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Apply a validated discount to a charge amount.
|
|
133
|
+
*
|
|
134
|
+
* The FIRST charge only — every code is `duration: 'once'`, so the renewal keeps
|
|
135
|
+
* the full price and callers only ever hand this the amount being charged now.
|
|
136
|
+
* Mirrors what a Stripe coupon does to the first invoice: `percent` is Stripe's
|
|
137
|
+
* `percent_off`, `amount` its `amount_off` (in dollars here, not cents).
|
|
138
|
+
*
|
|
139
|
+
* @param {number} amount - The undiscounted charge (e.g., 99.99)
|
|
140
|
+
* @param {object} [discount] - A validate() result, or null for no discount
|
|
141
|
+
* @returns {number} The discounted charge, never below 0 (e.g., 84.99)
|
|
142
|
+
*/
|
|
143
|
+
function applyToAmount(amount, discount) {
|
|
144
|
+
const base = Number(amount) || 0;
|
|
145
|
+
|
|
146
|
+
if (!discount || discount.valid === false) {
|
|
147
|
+
return base;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// `base * percent / 100`, in that order, is not a style choice: the callers this
|
|
151
|
+
// function was folded out of all associated it that way, and `base * (percent /
|
|
152
|
+
// 100)` differs by an ULP often enough to flip a half-cent rounding (a $0.05
|
|
153
|
+
// charge at 10% off rounds to $0.05 one way and $0.04 the other)
|
|
154
|
+
const off = discount.percent > 0
|
|
155
|
+
? base * discount.percent / 100
|
|
156
|
+
: (discount.amount || 0);
|
|
157
|
+
|
|
158
|
+
return Math.max(0, parseFloat((base - off).toFixed(2)));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The first charge for a provider that has no coupon object — applyToAmount()
|
|
163
|
+
* with the zero-total refusal in front of it.
|
|
164
|
+
*
|
|
165
|
+
* Stripe and Chargebee hand their hosted page a real coupon and let it decide
|
|
166
|
+
* what a zero total means. PayPal and Coinbase are prices THIS framework
|
|
167
|
+
* computes and sends, and neither a PayPal v2 Order/setup fee nor a Coinbase
|
|
168
|
+
* charge accepts a zero amount — so a code that covered the whole price was
|
|
169
|
+
* sent as a real $0.00 charge and came back as a provider 400 the buyer read as
|
|
170
|
+
* the checkout's generic failure sentence
|
|
171
|
+
* ([#786](https://github.com/Omega-JS-Stack/omega/issues/786)). It is refused
|
|
172
|
+
* here instead, before the provider is called at all, and the refusal is coded
|
|
173
|
+
* 400 so `POST /payments/intent` answers the buyer with THESE words (naming
|
|
174
|
+
* their code and the price) rather than its neutral 500 line.
|
|
175
|
+
*
|
|
176
|
+
* A product priced 0 is NOT this case: it carries no code that could have taken
|
|
177
|
+
* anything off, and every provider already refuses it with its own "No price
|
|
178
|
+
* configured for …" — which stays theirs.
|
|
179
|
+
*
|
|
180
|
+
* @param {number} listPrice - The charge before any code
|
|
181
|
+
* @param {object} [discount] - A validate() result, or null for no discount
|
|
182
|
+
* @param {object} options
|
|
183
|
+
* @param {string} options.provider - The provider's display name, for the message
|
|
184
|
+
* @returns {number} The discounted charge, always above zero
|
|
185
|
+
* @throws {Error} Coded 400 when the code leaves nothing to charge
|
|
186
|
+
*/
|
|
187
|
+
function chargeableAmount(listPrice, discount, { provider }) {
|
|
188
|
+
const amount = applyToAmount(listPrice, discount);
|
|
189
|
+
|
|
190
|
+
// A priced product that discounts to nothing can only have got there through a
|
|
191
|
+
// code — applyToAmount() returns the base untouched without one — so the
|
|
192
|
+
// refusal can always name it
|
|
193
|
+
if (listPrice > 0 && amount <= 0) {
|
|
194
|
+
const error = new Error(`Discount code ${discount.code} covers the full $${Number(listPrice).toFixed(2)} price, so there is nothing for ${provider} to charge. Remove the code or choose another payment method.`);
|
|
195
|
+
|
|
196
|
+
error.code = 400;
|
|
197
|
+
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return amount;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = { validate, applyToAmount, chargeableAmount, promoShape, DISCOUNT_CODES };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const isAlreadyGone = require('./provider-errors.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The ONE way a provider library reports a lookup it could not answer.
|
|
5
|
+
*
|
|
6
|
+
* `fetchResource()` used to swallow its own failure and hand back the payload the
|
|
7
|
+
* WEBHOOK carried, flagged stale — so an unverified object supplied by whoever
|
|
8
|
+
* posted the event drove real subscription state and real conversions. The
|
|
9
|
+
* provider's own answer is the only trusted source, so a lookup that fails
|
|
10
|
+
* produces no resource at all ([#506](https://github.com/Omega-JS-Stack/omega/issues/506)).
|
|
11
|
+
*
|
|
12
|
+
* What the caller still needs is WHICH failure it was, because the two have
|
|
13
|
+
* opposite outcomes:
|
|
14
|
+
*
|
|
15
|
+
* - **not found** (`notFound: true`) — the provider affirmatively does not have
|
|
16
|
+
* this resource. Nothing will ever make it processable, so the pipeline refuses
|
|
17
|
+
* the event and acknowledges it rather than redelivering forever.
|
|
18
|
+
* - **unreachable** (`notFound: false`) — a timeout, a 5xx, an expired key. The
|
|
19
|
+
* answer exists; this attempt could not read it. The pipeline defers, and the
|
|
20
|
+
* retry ladder is the reconciliation mechanism.
|
|
21
|
+
*
|
|
22
|
+
* The split itself is [provider-errors.js](provider-errors.js), so every provider
|
|
23
|
+
* classifies by the same rule instead of each naming its own not-found shape.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Wrap a failed provider lookup as the classified error the pipeline branches on
|
|
28
|
+
*
|
|
29
|
+
* @param {Error} error - The error the provider call threw
|
|
30
|
+
* @param {object} options
|
|
31
|
+
* @param {string} options.provider - Provider name (e.g. 'stripe')
|
|
32
|
+
* @param {string} options.fn - The library method that made the call, so the message names its own call site (e.g. 'getRefundDetails')
|
|
33
|
+
* @param {string} options.resourceType - Resource type that was being fetched
|
|
34
|
+
* @param {string} options.resourceId - Resource ID that was being fetched
|
|
35
|
+
* @param {string} [options.consequence] - What the failed call did NOT do (e.g. an uncaptured capture)
|
|
36
|
+
* @returns {Error} The error to throw, carrying `notFound` plus what it was about
|
|
37
|
+
*/
|
|
38
|
+
function fetchFailure(error, { provider, fn, resourceType, resourceId, consequence }) {
|
|
39
|
+
const notFound = isAlreadyGone(error);
|
|
40
|
+
const verdict = notFound
|
|
41
|
+
? `${provider} does not have ${resourceType} ${resourceId}`
|
|
42
|
+
: `${provider} could not be reached for ${resourceType} ${resourceId}`;
|
|
43
|
+
const suffix = consequence ? ` — ${consequence}` : '';
|
|
44
|
+
|
|
45
|
+
const failure = new Error(`${provider} ${fn}(${resourceType}/${resourceId}) failed — ${verdict}: ${error?.message || error}${suffix}`);
|
|
46
|
+
|
|
47
|
+
failure.notFound = notFound;
|
|
48
|
+
failure.provider = provider;
|
|
49
|
+
failure.resourceType = resourceType;
|
|
50
|
+
failure.resourceId = resourceId;
|
|
51
|
+
failure.cause = error;
|
|
52
|
+
|
|
53
|
+
return failure;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = fetchFailure;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The payment half of the OMEGA license
|
|
3
|
+
* ([#320](https://github.com/Omega-JS-Stack/omega/issues/320)).
|
|
4
|
+
*
|
|
5
|
+
* A published OMEGA install needs a license to run the payment system live.
|
|
6
|
+
* The check itself is a DEPLOY-time question the CLI asks
|
|
7
|
+
* (@omega.js/devkit/license) — this runtime never phones home. What reaches
|
|
8
|
+
* here is the verdict the deploy composed into the artifact's own .env:
|
|
9
|
+
*
|
|
10
|
+
* OMEGA_LICENSE_STATUS=licensed → nothing changes
|
|
11
|
+
* OMEGA_LICENSE_STATUS=keyless → the real providers refuse to initialize
|
|
12
|
+
* (absent) → nothing changes
|
|
13
|
+
*
|
|
14
|
+
* ABSENT is the important case: only a deploy writes the key, so every local
|
|
15
|
+
* lane — the emulator, `omega serve`, every test lane, a demo-* project —
|
|
16
|
+
* behaves exactly as it did before this existed. The `test` provider is never
|
|
17
|
+
* gated either: "payments gated" MEANS test mode still works (spec call 5).
|
|
18
|
+
*
|
|
19
|
+
* One gate, called from the three real providers' init(). They share no entry
|
|
20
|
+
* module to hold it, so the assertion lives here and each init calls it in one
|
|
21
|
+
* line rather than three copies of the rule.
|
|
22
|
+
*/
|
|
23
|
+
const env = require('../env.js');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Refuse live payment processing on a keyless deploy.
|
|
27
|
+
*
|
|
28
|
+
* @param {string} provider - The provider being initialized (names the refusal).
|
|
29
|
+
* @throws {Error} UnlicensedPaymentsError (code 500) when the deploy was keyless.
|
|
30
|
+
*/
|
|
31
|
+
function assertLicensedPayments(provider) {
|
|
32
|
+
if (env.get('OMEGA_LICENSE_STATUS') !== 'keyless') { return; }
|
|
33
|
+
|
|
34
|
+
const error = new Error(
|
|
35
|
+
`${provider} is disabled: this backend was deployed WITHOUT an OMEGA license, so live payment processing is off. `
|
|
36
|
+
+ 'A license is a subscription on omegajs.dev; put its account API key in the brand .env as OMEGA_LICENSE_KEY and deploy again. '
|
|
37
|
+
+ 'Test-mode payments keep working without one.',
|
|
38
|
+
);
|
|
39
|
+
error.name = 'UnlicensedPaymentsError';
|
|
40
|
+
error.code = 500;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = assertLicensedPayments;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
|
|
3
|
+
// How many ids one mint may try before it gives up. 12 random digits is a
|
|
4
|
+
// trillion-wide space, so a run that collides this many times in a row is not
|
|
5
|
+
// bad luck — it is a broken generator or a broken read, and both are worth
|
|
6
|
+
// hearing about ([#664](https://github.com/Omega-JS-Stack/omega/issues/664)).
|
|
7
|
+
const MAX_ATTEMPTS = 5;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate a unique order ID in the format XXXX-XXXX-XXXX
|
|
11
|
+
* 12 random digits, grouped in 3 segments of 4
|
|
12
|
+
*
|
|
13
|
+
* @returns {string} e.g. '4637-8821-0473'
|
|
14
|
+
*/
|
|
15
|
+
function generate() {
|
|
16
|
+
const bytes = crypto.randomBytes(6);
|
|
17
|
+
const digits = Array.from(bytes)
|
|
18
|
+
.map(b => (b % 100).toString().padStart(2, '0'))
|
|
19
|
+
.join('');
|
|
20
|
+
|
|
21
|
+
return `${digits.slice(0, 4)}-${digits.slice(4, 8)}-${digits.slice(8, 12)}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Mint an order id no intent already holds.
|
|
26
|
+
*
|
|
27
|
+
* The id keys `payments-intents/<orderId>` (and `payments-orders/<orderId>`
|
|
28
|
+
* after it), so a repeat does not collide harmlessly — it OVERWRITES another
|
|
29
|
+
* customer's intent, and hands both purchases the same analytics dedupe id. The
|
|
30
|
+
* odds are small and they grow with volume, which is exactly the shape of bug
|
|
31
|
+
* that is cheap now and unfixable later.
|
|
32
|
+
*
|
|
33
|
+
* An exhausted mint throws: an id that is already taken must never be handed
|
|
34
|
+
* back, and there is nothing else this can return.
|
|
35
|
+
*
|
|
36
|
+
* @param {object} options
|
|
37
|
+
* @param {object} options.admin - The firebase-admin app
|
|
38
|
+
* @param {object} options.ctx - RouteContext, for the collision record
|
|
39
|
+
* @param {function} [options.generate] - The id source, injectable so a collision can be produced on demand
|
|
40
|
+
* @returns {Promise<string>} An order id no intent doc holds
|
|
41
|
+
*/
|
|
42
|
+
async function mint({ admin, ctx, generate: generateId = generate }) {
|
|
43
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
44
|
+
const orderId = generateId();
|
|
45
|
+
const existing = await admin.firestore().doc(`payments-intents/${orderId}`).get();
|
|
46
|
+
|
|
47
|
+
if (!existing.exists) {
|
|
48
|
+
return orderId;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
ctx.warn(`Order id collision: payments-intents/${orderId} already exists, minting another (attempt ${attempt}/${MAX_ATTEMPTS})`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
throw new Error(`Could not mint an unused order id in ${MAX_ATTEMPTS} attempts`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = { generate, mint, MAX_ATTEMPTS };
|