@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,573 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversion match data — everything a platform needs to tie a SERVER event back
|
|
3
|
+
* to the person who clicked the ad
|
|
4
|
+
* ([#385](https://github.com/Omega-JS-Stack/omega/issues/385), stage D of
|
|
5
|
+
* [#302](https://github.com/Omega-JS-Stack/omega/issues/302)).
|
|
6
|
+
*
|
|
7
|
+
* Two halves, because the adapters already own the split:
|
|
8
|
+
*
|
|
9
|
+
* buildAttributionContext() — the FLAT attribution the adapters read out of
|
|
10
|
+
* `context.attribution`: GA4 takes the campaign fields as event params,
|
|
11
|
+
* Meta takes `fbc`/`fbp` and TikTok `ttclid`/`ttp` into the descriptor's
|
|
12
|
+
* `userData` match block, and both take the touch's page (`url`/`referrer`)
|
|
13
|
+
* into the descriptor's own `page` member. What each provider wants is the
|
|
14
|
+
* adapter's call, never a caller's.
|
|
15
|
+
*
|
|
16
|
+
* buildIdentity() — who the person is: the uid, their hashed email/phone, the
|
|
17
|
+
* IP + user agent of the request that started this, and EVERY other match
|
|
18
|
+
* parameter the platforms accept off the account doc — name, city, state,
|
|
19
|
+
* zip, country, date of birth, gender
|
|
20
|
+
* ([#577](https://github.com/Omega-JS-Stack/omega/issues/577)). Each sender
|
|
21
|
+
* maps these into its own spec's key names.
|
|
22
|
+
*
|
|
23
|
+
* RAW PII NEVER LEAVES. Every personal value is SHA256 hex, the same mechanism
|
|
24
|
+
* the GA4 Measurement Protocol helper uses (`helpers/analytics.js`) — with the
|
|
25
|
+
* normalization each platform requires on top, because an unnormalized hash
|
|
26
|
+
* matches nobody. Email is the one value everybody normalizes alike (trimmed +
|
|
27
|
+
* lowercased); the PHONE is not (#392): Meta's advanced matching hashes bare
|
|
28
|
+
* digits, GA4's Measurement Protocol and TikTok's Events API both hash the E.164
|
|
29
|
+
* form WITH the `+`. So the identity block carries BOTH digests under the same
|
|
30
|
+
* key names the browser half uses (`web core/js/libs/analytics.js`), and each
|
|
31
|
+
* sender picks its own.
|
|
32
|
+
*
|
|
33
|
+
* ONE TABLE PER PROVIDER, and no shared "close enough" normalizer: the rules
|
|
34
|
+
* genuinely differ key by key (Meta wants a state as the 2-letter ANSI code and
|
|
35
|
+
* a country lowercase; GA4 wants the region NAME and the country UPPERCASE), and
|
|
36
|
+
* a value normalized by the wrong platform's rule is accepted by the API and
|
|
37
|
+
* matched to nobody. Both tables were written against the platforms' live specs
|
|
38
|
+
* (fetched 2026-08-24), each cited above its table below.
|
|
39
|
+
*
|
|
40
|
+
* TIKTOK gets no personal table because its Events API has no parameter to put
|
|
41
|
+
* one in: the 2.0 `user` object documents email, phone, external_id, ttclid,
|
|
42
|
+
* ttp, ip and user_agent, full stop.
|
|
43
|
+
*
|
|
44
|
+
* The email/phone/external-id normalizers are the shared package's —
|
|
45
|
+
* `@omega.js/analytics/identity` is where a spec is written down once for BOTH
|
|
46
|
+
* halves of a conversion. Only the digest is local: the shared `sha256()` is
|
|
47
|
+
* async (a page's only hash is `crypto.subtle`), and everything here is sync.
|
|
48
|
+
* The rules below are the ones written down here instead, for the reason the
|
|
49
|
+
* NAME rule (#403) always was: no browser surface sends any of these, so the
|
|
50
|
+
* shared package carries no key for them — the day one does, they move there
|
|
51
|
+
* with the rest.
|
|
52
|
+
*
|
|
53
|
+
* Everything here tolerates absence. The raw-API recovery lane writes orders with
|
|
54
|
+
* no attribution and no request context at all, and a fire with external_id alone
|
|
55
|
+
* is worth more than a throw.
|
|
56
|
+
*/
|
|
57
|
+
const crypto = require('crypto');
|
|
58
|
+
|
|
59
|
+
// @omega.js/analytics is a private workspace package: in the monorepo the bare
|
|
60
|
+
// specifier resolves via the workspace link (and the prepare-package vendor hook
|
|
61
|
+
// rewrites it in dist/), but src/ ships in the tarball UNREWRITTEN and the test
|
|
62
|
+
// corpus deep-requires it in consumers — so fall back to the copy vendored into
|
|
63
|
+
// dist/, which sits at the same depth from both trees.
|
|
64
|
+
let normalizeEmail;
|
|
65
|
+
let normalizeExternalId;
|
|
66
|
+
let metaPhone;
|
|
67
|
+
let tiktokPhone;
|
|
68
|
+
try {
|
|
69
|
+
({ normalizeEmail, normalizeExternalId, metaPhone, tiktokPhone } = require('../../../vendor/analytics/identity.js'));
|
|
70
|
+
} catch (e) {
|
|
71
|
+
({ normalizeEmail, normalizeExternalId, metaPhone, tiktokPhone } = require('../../../../dist/vendor/analytics/identity.js'));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// The campaign params GA4's Measurement Protocol reads, and the utm key each one
|
|
75
|
+
// is captured under by the landing-page capture (`web core/js/core/query-strings.js`).
|
|
76
|
+
const CAMPAIGN_PARAMS = {
|
|
77
|
+
source: 'utm_source',
|
|
78
|
+
medium: 'utm_medium',
|
|
79
|
+
campaign: 'utm_campaign',
|
|
80
|
+
term: 'utm_term',
|
|
81
|
+
content: 'utm_content',
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* SHA256 hex, the hashing every platform's match spec asks for.
|
|
86
|
+
* @param {string} value - The already-normalized value.
|
|
87
|
+
* @returns {string} Lowercase hex digest.
|
|
88
|
+
*/
|
|
89
|
+
function toSHA256(value) {
|
|
90
|
+
return crypto.createHash('sha256').update(value).digest('hex');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Hash an email address per Meta/TikTok spec: trimmed, lowercased, then SHA256.
|
|
95
|
+
* @param {string} [email]
|
|
96
|
+
* @returns {string|null} The digest, or null when there is no email.
|
|
97
|
+
*/
|
|
98
|
+
function hashEmail(email) {
|
|
99
|
+
const normalized = normalizeEmail(email);
|
|
100
|
+
|
|
101
|
+
return normalized ? toSHA256(normalized) : null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// META's customer-information table
|
|
106
|
+
// https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
|
|
107
|
+
// Every parameter below is "Hashing required", each with its own normalization.
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
// The 2-character ANSI abbreviation Meta's `st` asks for, by the name a
|
|
111
|
+
// geolocation header writes it under (`cf-region` sends "California" where
|
|
112
|
+
// `x-appengine-region` sends "ca"). A state Meta cannot be given as its code is
|
|
113
|
+
// a state matched to nobody, so the lookup is the difference between sending the
|
|
114
|
+
// key and wasting it. Non-US states fall through to Meta's own second rule.
|
|
115
|
+
const US_STATE_CODES = {
|
|
116
|
+
alabama: 'al', alaska: 'ak', arizona: 'az', arkansas: 'ar', california: 'ca',
|
|
117
|
+
colorado: 'co', connecticut: 'ct', delaware: 'de', 'district of columbia': 'dc',
|
|
118
|
+
florida: 'fl', georgia: 'ga', hawaii: 'hi', idaho: 'id', illinois: 'il',
|
|
119
|
+
indiana: 'in', iowa: 'ia', kansas: 'ks', kentucky: 'ky', louisiana: 'la',
|
|
120
|
+
maine: 'me', maryland: 'md', massachusetts: 'ma', michigan: 'mi',
|
|
121
|
+
minnesota: 'mn', mississippi: 'ms', missouri: 'mo', montana: 'mt',
|
|
122
|
+
nebraska: 'ne', nevada: 'nv', 'new hampshire': 'nh', 'new jersey': 'nj',
|
|
123
|
+
'new mexico': 'nm', 'new york': 'ny', 'north carolina': 'nc',
|
|
124
|
+
'north dakota': 'nd', ohio: 'oh', oklahoma: 'ok', oregon: 'or',
|
|
125
|
+
pennsylvania: 'pa', 'rhode island': 'ri', 'south carolina': 'sc',
|
|
126
|
+
'south dakota': 'sd', tennessee: 'tn', texas: 'tx', utah: 'ut',
|
|
127
|
+
vermont: 'vt', virginia: 'va', washington: 'wa', 'west virginia': 'wv',
|
|
128
|
+
wisconsin: 'wi', wyoming: 'wy', 'puerto rico': 'pr',
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Meta's text rule: lowercase, no punctuation, UTF-8 left alone. `\p{P}\p{S}`
|
|
133
|
+
* is punctuation AND symbols, so `O'Byrne` and `Ada-Marie` normalize the way
|
|
134
|
+
* Meta's own parameter builder does rather than hashing their apostrophes.
|
|
135
|
+
*
|
|
136
|
+
* @param {string} [value]
|
|
137
|
+
* @param {boolean} [spaces] - Keep internal spaces (names) or drop them (city,
|
|
138
|
+
* state — Meta's own city example is `newyork`).
|
|
139
|
+
* @returns {string} The normalized value, or '' when there is nothing to send.
|
|
140
|
+
*/
|
|
141
|
+
function metaText(value, spaces = true) {
|
|
142
|
+
const stripped = `${value ?? ''}`.toLowerCase().replace(/[\p{P}\p{S}]/gu, '');
|
|
143
|
+
|
|
144
|
+
return (spaces ? stripped.trim().replace(/\s+/g, ' ') : stripped.replace(/\s+/gu, '')).trim();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Meta `ct`: the text rule with the spaces out too — its own example is `newyork`. */
|
|
148
|
+
function metaCity(value) {
|
|
149
|
+
return metaText(value, false);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Meta `st`: the 2-character ANSI code in lowercase; other countries' own rule. */
|
|
153
|
+
function metaState(value) {
|
|
154
|
+
return US_STATE_CODES[metaText(value)] || metaCity(value);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Meta `zp`: lowercase, no spaces and no dash, and the first FIVE digits of a US
|
|
159
|
+
* zip. An all-digit code longer than five is a zip+4 (`94035-1234`); the shorter
|
|
160
|
+
* numeric codes other countries use are left whole.
|
|
161
|
+
*/
|
|
162
|
+
function metaZip(value) {
|
|
163
|
+
const normalized = `${value ?? ''}`.toLowerCase().replace(/[\s-]/g, '');
|
|
164
|
+
|
|
165
|
+
return /^\d{6,}$/.test(normalized) ? normalized.slice(0, 5) : normalized;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Meta `country`: the ISO 3166-1 alpha-2 code, lowercase. A country NAME is not
|
|
170
|
+
* a code — hashing `unitedstates` would send a key nobody matches on, which is
|
|
171
|
+
* worse than the absent key an empty string compacts into.
|
|
172
|
+
*/
|
|
173
|
+
function metaCountry(value) {
|
|
174
|
+
const normalized = `${value ?? ''}`.trim().toLowerCase();
|
|
175
|
+
|
|
176
|
+
return /^[a-z]{2}$/.test(normalized) ? normalized : '';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Meta `db`: YYYYMMDD. The account schema stores a birthday as the `$timestamp`
|
|
181
|
+
* pair, and UTC is what it was stamped in.
|
|
182
|
+
*
|
|
183
|
+
* THE EPOCH IS NOT A BIRTHDAY. That pair's default is `1970-01-01` /
|
|
184
|
+
* `timestampUNIX: 0`, so hashing it would hand every account with nothing on
|
|
185
|
+
* file the digest of `19700101` — one junk match key shared by all of them, the
|
|
186
|
+
* same trap `personal.telephone`'s `0` default is (#388).
|
|
187
|
+
*
|
|
188
|
+
* @param {object|string|number} [birthday] - `{ timestamp, timestampUNIX }`, an
|
|
189
|
+
* ISO string, or epoch millis.
|
|
190
|
+
* @returns {string} The date, or '' when there is none (or it is unparseable).
|
|
191
|
+
*/
|
|
192
|
+
function metaDateOfBirth(birthday) {
|
|
193
|
+
const raw = birthday?.timestamp ?? birthday;
|
|
194
|
+
const date = new Date(raw ?? '');
|
|
195
|
+
|
|
196
|
+
if (Number.isNaN(date.getTime()) || date.getTime() === 0) {
|
|
197
|
+
return '';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return date.toISOString().slice(0, 10).replace(/-/g, '');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Meta `ge`: the lowercase initial, and Meta accepts exactly two of them. */
|
|
204
|
+
function metaGender(value) {
|
|
205
|
+
const initial = `${value ?? ''}`.trim().toLowerCase().charAt(0);
|
|
206
|
+
|
|
207
|
+
return initial === 'f' || initial === 'm' ? initial : '';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// The table itself: Meta's key → where the value comes from on the account, and
|
|
211
|
+
// the rule its own spec states. `buildMetaMatch()` walks it, so adding a
|
|
212
|
+
// parameter is one row and no branching anywhere else.
|
|
213
|
+
const META_MATCH = {
|
|
214
|
+
fn: { from: 'firstName', normalize: metaText },
|
|
215
|
+
ln: { from: 'lastName', normalize: metaText },
|
|
216
|
+
ct: { from: 'city', normalize: metaCity },
|
|
217
|
+
st: { from: 'state', normalize: metaState },
|
|
218
|
+
zp: { from: 'zip', normalize: metaZip },
|
|
219
|
+
country: { from: 'country', normalize: metaCountry },
|
|
220
|
+
db: { from: 'dateOfBirth', normalize: metaDateOfBirth },
|
|
221
|
+
ge: { from: 'gender', normalize: metaGender },
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Meta's customer-information block for one person, already in Meta's own key
|
|
226
|
+
* names because the normalization is Meta's own.
|
|
227
|
+
*
|
|
228
|
+
* @param {object} fields - The shared reader's output (`readUserMatchFields`).
|
|
229
|
+
* @returns {object} Only the parameters that normalized to something.
|
|
230
|
+
*/
|
|
231
|
+
function buildMetaMatch(fields) {
|
|
232
|
+
const block = {};
|
|
233
|
+
|
|
234
|
+
for (const [key, { from, normalize }] of Object.entries(META_MATCH)) {
|
|
235
|
+
const normalized = normalize(fields[from]);
|
|
236
|
+
|
|
237
|
+
if (normalized) {
|
|
238
|
+
block[key] = toSHA256(normalized);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return block;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
// GA4's user-data table
|
|
247
|
+
// https://developers.google.com/analytics/devguides/collection/ga4/uid-data
|
|
248
|
+
// Names and street are HASHED; city, region, postal code and country ride in
|
|
249
|
+
// the clear — and none of these rules is Meta's.
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* GA4's text rule: digits and symbol characters removed, lowercase, trimmed.
|
|
254
|
+
* @param {string} [value]
|
|
255
|
+
* @param {boolean} [keepDigits] - The street's exception (its number is the point).
|
|
256
|
+
* @returns {string} The normalized value, or '' when there is nothing to send.
|
|
257
|
+
*/
|
|
258
|
+
function ga4Text(value, keepDigits = false) {
|
|
259
|
+
return `${value ?? ''}`
|
|
260
|
+
.toLowerCase()
|
|
261
|
+
.replace(keepDigits ? /[\p{P}\p{S}]/gu : /[\p{P}\p{S}\d]/gu, '')
|
|
262
|
+
.replace(/\s+/gu, ' ')
|
|
263
|
+
.trim();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** GA4 `address.sha256_first_name` / `sha256_last_name`. */
|
|
267
|
+
function hashGA4Name(name) {
|
|
268
|
+
const normalized = ga4Text(name);
|
|
269
|
+
|
|
270
|
+
return normalized ? toSHA256(normalized) : null;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** GA4 `address.sha256_street` — the one text key whose digits stay (the number). */
|
|
274
|
+
function hashGA4Street(street) {
|
|
275
|
+
const normalized = ga4Text(street, true);
|
|
276
|
+
|
|
277
|
+
return normalized ? toSHA256(normalized) : null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** GA4 `address.city` / `address.region`: normalized, never hashed. */
|
|
281
|
+
function ga4Place(value) {
|
|
282
|
+
return ga4Text(value);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** GA4 `address.postal_code`: only `.` and `~` come out, and it is never hashed. */
|
|
286
|
+
function ga4PostalCode(value) {
|
|
287
|
+
return `${value ?? ''}`.replace(/[.~]/g, '').trim();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** GA4 `address.country`: ISO 3166-1 alpha-2, UPPERCASE (its own sample sends `US`). */
|
|
291
|
+
function ga4Country(value) {
|
|
292
|
+
const normalized = `${value ?? ''}`.trim().toUpperCase();
|
|
293
|
+
|
|
294
|
+
return /^[A-Z]{2}$/.test(normalized) ? normalized : '';
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* The bare digits of a stored phone — country code included, no `+`, no
|
|
299
|
+
* punctuation — which is what both normalizations are built from.
|
|
300
|
+
*
|
|
301
|
+
* The account schema stores `{ countryCode, national }` as NUMBERS defaulting to
|
|
302
|
+
* 0, and 0 means "no phone on file" — hashing it would hand every phoneless
|
|
303
|
+
* account the same junk match key and poison the audience.
|
|
304
|
+
*
|
|
305
|
+
* @param {object|string} [telephone] - The user doc's `personal.telephone`
|
|
306
|
+
* ({ countryCode, national }), or a plain E.164 string (Auth's `phoneNumber`).
|
|
307
|
+
* @returns {string} The digits, or '' when there is no number.
|
|
308
|
+
*/
|
|
309
|
+
function phoneDigits(telephone) {
|
|
310
|
+
if (typeof telephone === 'string') {
|
|
311
|
+
return metaPhone(telephone);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!telephone?.national) {
|
|
315
|
+
return '';
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return metaPhone(`${telephone.countryCode || ''}${telephone.national}`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Hash a phone number per META's advanced-matching spec: digits only (country
|
|
323
|
+
* code included, no `+`, no punctuation), then SHA256.
|
|
324
|
+
*
|
|
325
|
+
* @param {object|string} [telephone] - `{ countryCode, national }`, or an E.164 string.
|
|
326
|
+
* @returns {string|null} The digest, or null when there is no number.
|
|
327
|
+
*/
|
|
328
|
+
function hashPhone(telephone) {
|
|
329
|
+
const digits = phoneDigits(telephone);
|
|
330
|
+
|
|
331
|
+
return digits ? toSHA256(digits) : null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Hash a phone number in E.164 WITH the leading `+`, then SHA256 — what GA4's
|
|
336
|
+
* Measurement Protocol and TikTok's Events API both ask for. A different digest
|
|
337
|
+
* for the same person than `hashPhone()`, which is the entire point (#392).
|
|
338
|
+
*
|
|
339
|
+
* @param {object|string} [telephone] - `{ countryCode, national }`, or an E.164 string.
|
|
340
|
+
* @returns {string|null} The digest, or null when there is no number.
|
|
341
|
+
*/
|
|
342
|
+
function hashPhoneE164(telephone) {
|
|
343
|
+
const e164 = tiktokPhone(phoneDigits(telephone));
|
|
344
|
+
|
|
345
|
+
return e164 ? toSHA256(e164) : null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Hash the uid the way TIKTOK's Events API demands of `external_id`: trimmed,
|
|
350
|
+
* then SHA256 ([#410](https://github.com/Omega-JS-Stack/omega/issues/410)).
|
|
351
|
+
*
|
|
352
|
+
* Verified against the live docs, because a raw id here was the #397 failure
|
|
353
|
+
* mode again — accepted by the API and matched to nobody. TikTok's
|
|
354
|
+
* `/event/track/` reference: "external_id ... SHA-256 hashing is required", and
|
|
355
|
+
* its Advanced Matching table takes the pixel half "Unhashed or hashed SHA-256.
|
|
356
|
+
* Trim any leading and trailing spaces before hashing and ensure you are
|
|
357
|
+
* consistent with the External ID used" — so the browser half hashes the same
|
|
358
|
+
* uid the same way and the two halves still meet. The trim rule itself is the
|
|
359
|
+
* shared package's `normalizeExternalId()`, like every other normalizer here:
|
|
360
|
+
* one home, so the two halves cannot drift apart a character at a time.
|
|
361
|
+
*
|
|
362
|
+
* META is the deliberate exception and stays RAW on `identity.externalId`: its
|
|
363
|
+
* customer-information reference marks external_id "Hashing recommended" (not
|
|
364
|
+
* required), and its own Pixel example passes a bare id — so the raw uid is
|
|
365
|
+
* what both Meta halves carry. GA4's sender needs it raw for a third reason:
|
|
366
|
+
* `Manager.Analytics({ uuid })` derives the `user_id` from it.
|
|
367
|
+
*
|
|
368
|
+
* @param {string} [uid] - The owner's uid.
|
|
369
|
+
* @returns {string|null} The digest, or null when there is no uid.
|
|
370
|
+
*/
|
|
371
|
+
function hashExternalId(uid) {
|
|
372
|
+
const normalized = normalizeExternalId(uid);
|
|
373
|
+
|
|
374
|
+
return normalized ? toSHA256(normalized) : null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* The touch a conversion is credited to: last touch when there is one, else first.
|
|
379
|
+
*
|
|
380
|
+
* Last-touch is only ever written by a TAGGED visit (#384), so falling back to
|
|
381
|
+
* first is what gives an organic-then-direct user their campaign back.
|
|
382
|
+
*
|
|
383
|
+
* @param {object} [attribution] - The order/user `attribution` object.
|
|
384
|
+
* @returns {object} The winning touch, or {} when there is none.
|
|
385
|
+
*/
|
|
386
|
+
function resolveTouch(attribution) {
|
|
387
|
+
return attribution?.last || attribution?.first || {};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Meta's `fbc` from a click id, per its spec: `fb.<subdomainIndex>.<creationTime>.<fbclid>`.
|
|
392
|
+
*
|
|
393
|
+
* The client only ever sends REAL cookies, so this is the server's half of the
|
|
394
|
+
* deal: a visitor who landed on an ad but whose `_fbc` cookie never made it to
|
|
395
|
+
* checkout (a different device, a cleared cookie jar, an ITP-shortened lifetime)
|
|
396
|
+
* still matches, because the fbclid was captured at landing and rode the order.
|
|
397
|
+
*
|
|
398
|
+
* subdomainIndex is 1 — the cookie the Pixel would have written lives on the
|
|
399
|
+
* brand's own domain. creationTime is the moment the click id was CAPTURED (the
|
|
400
|
+
* touch's timestamp), which is what the cookie would have carried.
|
|
401
|
+
*
|
|
402
|
+
* @param {object} touch - The winning touch.
|
|
403
|
+
* @returns {string|null} The constructed fbc, or null with no fbclid to build from.
|
|
404
|
+
*/
|
|
405
|
+
function constructFbc(touch) {
|
|
406
|
+
const fbclid = touch?.clickIds?.fbclid;
|
|
407
|
+
|
|
408
|
+
if (!fbclid) {
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const captured = Date.parse(touch.timestamp || '');
|
|
413
|
+
const creationTime = Number.isNaN(captured) ? Date.now() : captured;
|
|
414
|
+
|
|
415
|
+
return `fb.1.${creationTime}.${fbclid}`;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* The flat attribution context the adapters read.
|
|
420
|
+
*
|
|
421
|
+
* @param {object} [attribution] - The order/user `attribution` — { first, last, affiliate, cookies }.
|
|
422
|
+
* @returns {object} Only the keys that resolved to a value.
|
|
423
|
+
*/
|
|
424
|
+
function buildAttributionContext(attribution) {
|
|
425
|
+
const touch = resolveTouch(attribution);
|
|
426
|
+
const cookies = attribution?.cookies || {};
|
|
427
|
+
const clickIds = touch.clickIds || {};
|
|
428
|
+
const tags = touch.tags || {};
|
|
429
|
+
|
|
430
|
+
const context = {
|
|
431
|
+
// GA4's campaign vocabulary (the adapter lifts these into the event params)
|
|
432
|
+
...Object.fromEntries(
|
|
433
|
+
Object.entries(CAMPAIGN_PARAMS)
|
|
434
|
+
.map(([param, utmKey]) => [param, tags[utmKey]])
|
|
435
|
+
.filter(([, value]) => !!value)
|
|
436
|
+
),
|
|
437
|
+
|
|
438
|
+
// Meta's match keys: the real cookie wins, and a click id constructs one.
|
|
439
|
+
fbc: cookies.fbc || constructFbc(touch),
|
|
440
|
+
fbp: cookies.fbp,
|
|
441
|
+
|
|
442
|
+
// TikTok's match keys
|
|
443
|
+
ttclid: clickIds.ttclid,
|
|
444
|
+
ttp: cookies.ttp,
|
|
445
|
+
|
|
446
|
+
// Google Ads' click id. GA4 MP takes it as an event param rather than a
|
|
447
|
+
// match key — the Google Ads API's enhanced conversions (a FUTURE platform
|
|
448
|
+
// file, see conversions.js) is what consumes it as identity.
|
|
449
|
+
gclid: clickIds.gclid,
|
|
450
|
+
|
|
451
|
+
// The page the credited touch happened on. A server conversion fires from a
|
|
452
|
+
// webhook or an auth trigger and has no page of its own, so this is the only
|
|
453
|
+
// URL it can honestly claim — and both ad platforms read one (TikTok's
|
|
454
|
+
// `page: { url, referrer }`, Meta's `event_source_url`), so dropping it cost
|
|
455
|
+
// match quality on both ([#497](https://github.com/Omega-JS-Stack/omega/issues/497)).
|
|
456
|
+
// The adapters place it; a touch that carried none sends none.
|
|
457
|
+
url: touch.url,
|
|
458
|
+
referrer: touch.referrer,
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
return compact(context);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* The match values a user doc holds, by the name the tables above ask for them.
|
|
466
|
+
*
|
|
467
|
+
* The ONE reader (#577): every server-side caller hands `buildIdentity()` the
|
|
468
|
+
* doc and nothing else decides which key an address lives under. A call site
|
|
469
|
+
* that read `personal.location.region` itself is how `personal.telephone.number`
|
|
470
|
+
* — a field no account has ever carried — went unnoticed for a year (#388).
|
|
471
|
+
*
|
|
472
|
+
* `zip` is the PLATFORM's parameter name, so it stays the bag key the tables
|
|
473
|
+
* above normalize — the account schema calls the field
|
|
474
|
+
* `personal.location.postalCode`, because a postal code is not a US zip
|
|
475
|
+
* ([#663](https://github.com/Omega-JS-Stack/omega/issues/663)). It and
|
|
476
|
+
* `personal.location.street` are the account page's optional address fields; an
|
|
477
|
+
* account that left them empty sends no key, like any other absent value.
|
|
478
|
+
*
|
|
479
|
+
* @param {object} [user] - A `users/{uid}` doc.
|
|
480
|
+
* @returns {object} The flat field bag the per-provider tables normalize.
|
|
481
|
+
*/
|
|
482
|
+
function readUserMatchFields(user) {
|
|
483
|
+
const personal = user?.personal || {};
|
|
484
|
+
|
|
485
|
+
return {
|
|
486
|
+
email: user?.auth?.email,
|
|
487
|
+
telephone: personal.telephone,
|
|
488
|
+
firstName: personal.name?.first,
|
|
489
|
+
lastName: personal.name?.last,
|
|
490
|
+
city: personal.location?.city,
|
|
491
|
+
state: personal.location?.region,
|
|
492
|
+
zip: personal.location?.postalCode,
|
|
493
|
+
country: personal.location?.country,
|
|
494
|
+
street: personal.location?.street,
|
|
495
|
+
dateOfBirth: personal.birthday,
|
|
496
|
+
gender: personal.gender,
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Who the conversion belongs to.
|
|
502
|
+
*
|
|
503
|
+
* @param {object} options
|
|
504
|
+
* @param {string} options.uid - The owner's uid — the external_id every platform
|
|
505
|
+
* gets, raw for Meta and GA4, hashed for TikTok (`hashExternalId()`).
|
|
506
|
+
* @param {object} [options.user] - The owner's user doc, read by the ONE reader
|
|
507
|
+
* above for every personal parameter the platforms accept.
|
|
508
|
+
* @param {string} [options.email] - An email that beats the doc's (Firebase Auth's
|
|
509
|
+
* record on the signup path). Hashed here, never sent raw.
|
|
510
|
+
* @param {object|string} [options.telephone] - `{ countryCode, national }`, or an
|
|
511
|
+
* E.164 string; beats the doc's the same way.
|
|
512
|
+
* @param {object} [options.request] - The captured `{ ip, userAgent }` of the
|
|
513
|
+
* checkout intent, or of the post-auth request on a signup.
|
|
514
|
+
* @returns {object} Only the keys that resolved to a value.
|
|
515
|
+
*/
|
|
516
|
+
function buildIdentity({ uid, user, email, telephone, request }) {
|
|
517
|
+
const fields = readUserMatchFields(user);
|
|
518
|
+
const meta = buildMetaMatch(fields);
|
|
519
|
+
|
|
520
|
+
return compact({
|
|
521
|
+
externalId: uid || null,
|
|
522
|
+
// TikTok's Events API requires the digest where Meta only recommends it, so
|
|
523
|
+
// the id ships in both shapes and each sender picks its own (#410).
|
|
524
|
+
tiktokExternalIdHash: hashExternalId(uid),
|
|
525
|
+
emailHash: hashEmail(email || fields.email),
|
|
526
|
+
// One person, two digests — the normalization is the platform's, not ours.
|
|
527
|
+
metaPhoneHash: hashPhone(telephone || fields.telephone),
|
|
528
|
+
tiktokPhoneHash: hashPhoneE164(telephone || fields.telephone),
|
|
529
|
+
ip: request?.ip || null,
|
|
530
|
+
userAgent: request?.userAgent || null,
|
|
531
|
+
// META's customer-information set, in Meta's own key names — the only
|
|
532
|
+
// provider with parameters for any of it. Absent entirely when the account
|
|
533
|
+
// filled none of them, so a fire with nothing to say keeps saying nothing.
|
|
534
|
+
meta: Object.keys(meta).length ? meta : null,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Drop the keys nothing resolved for — a match block carrying `fbp: undefined`
|
|
539
|
+
// is noise the platforms read as a field we tried and failed to send.
|
|
540
|
+
function compact(object) {
|
|
541
|
+
const out = {};
|
|
542
|
+
|
|
543
|
+
for (const [key, value] of Object.entries(object)) {
|
|
544
|
+
if (value !== undefined && value !== null) {
|
|
545
|
+
out[key] = value;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return out;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
module.exports = {
|
|
553
|
+
buildAttributionContext,
|
|
554
|
+
buildIdentity,
|
|
555
|
+
readUserMatchFields,
|
|
556
|
+
constructFbc,
|
|
557
|
+
hashEmail,
|
|
558
|
+
hashExternalId,
|
|
559
|
+
hashPhone,
|
|
560
|
+
hashPhoneE164,
|
|
561
|
+
// Meta's table, and the walk over it — exported so the parameter list is
|
|
562
|
+
// readable (and testable) as the table it is
|
|
563
|
+
META_MATCH,
|
|
564
|
+
buildMetaMatch,
|
|
565
|
+
// GA4's table: the Measurement Protocol helper builds its own `user_data`
|
|
566
|
+
// block, from these rules and nobody else's
|
|
567
|
+
hashGA4Name,
|
|
568
|
+
hashGA4Street,
|
|
569
|
+
ga4Place,
|
|
570
|
+
ga4PostalCode,
|
|
571
|
+
ga4Country,
|
|
572
|
+
toSHA256,
|
|
573
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SERVER half of `sign_up` — one home for the registration conversion
|
|
3
|
+
* ([#577](https://github.com/Omega-JS-Stack/omega/issues/577)).
|
|
4
|
+
*
|
|
5
|
+
* `sign_up` is the catalog's one `placement: 'both'` event, so the two halves
|
|
6
|
+
* MUST deduplicate or every registration is counted twice.
|
|
7
|
+
*
|
|
8
|
+
* THE DEDUPE ID IS `sign_up.<uid>`.
|
|
9
|
+
*
|
|
10
|
+
* Meta's Conversions API deduplicates on the PAIR (`event_name`, `event_id`), and
|
|
11
|
+
* TikTok on `event_id` — so both halves have to name the same string, computed
|
|
12
|
+
* from something both sides hold before either fires. The uid is the only such
|
|
13
|
+
* thing: the browser has it the instant Firebase Auth resolves (it is what web's
|
|
14
|
+
* `trackSignup(method, user)` already reads), the server has it here, and it is
|
|
15
|
+
* unique per account for all time. Nothing derived from a clock could ever match
|
|
16
|
+
* across the two.
|
|
17
|
+
*
|
|
18
|
+
* Which is also why this half is META + TIKTOK ONLY: GA4 has no cross-source
|
|
19
|
+
* event_id deduplication, so a Measurement Protocol `sign_up` beside the
|
|
20
|
+
* browser's gtag one is simply two registrations. GA4 keeps its mapping in the
|
|
21
|
+
* catalog — the client half owns that provider (Ian's ruling, stage D).
|
|
22
|
+
*
|
|
23
|
+
* WHERE IT FIRES FROM is the #577 decision. It used to fire from the auth
|
|
24
|
+
* trigger (`events/auth/on-create.js`), which has no HTTP request behind it: no
|
|
25
|
+
* IP, no user agent, no `_fbc`/`_fbp`/`_ttp`, and an attribution the browser had
|
|
26
|
+
* not posted yet — Meta scored the result around 4/10 on match quality. It now
|
|
27
|
+
* fires from `routes/user/signup`, the post-auth request the browser ALREADY
|
|
28
|
+
* makes, which carries all four and runs behind that route's own
|
|
29
|
+
* `flags.signupProcessed` gate — so there is no race with the trigger's write
|
|
30
|
+
* (the route polls for the doc first) and no second fire to deduplicate against.
|
|
31
|
+
* The cost is deliberate and named: a surface that never posts that request
|
|
32
|
+
* (desktop, extension) fires no server half — and it never had match data worth
|
|
33
|
+
* sending anyway.
|
|
34
|
+
*/
|
|
35
|
+
const { deliverConversion } = require('./conversions.js');
|
|
36
|
+
const { buildAttributionContext, buildIdentity } = require('./match-data.js');
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Everything the fire is made of — pure, so the payload can be read without a
|
|
40
|
+
* route, a request or a platform.
|
|
41
|
+
*
|
|
42
|
+
* @param {object} options
|
|
43
|
+
* @param {object} options.authUser - The Firebase Auth record (uid, email, providerData).
|
|
44
|
+
* @param {object} [options.userRecord] - The user doc as it was just written —
|
|
45
|
+
* the attribution (cookies included), the consent snapshot, and every personal
|
|
46
|
+
* match parameter the shared reader takes off it.
|
|
47
|
+
* @param {object} [options.request] - The post-auth request's `{ ip, userAgent }`.
|
|
48
|
+
* @returns {object} The `deliverConversion` payload, minus its ctx + Manager.
|
|
49
|
+
*/
|
|
50
|
+
function buildSignupFire({ authUser, userRecord, request }) {
|
|
51
|
+
const uid = authUser.uid;
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
event: 'sign_up',
|
|
55
|
+
params: {
|
|
56
|
+
method: resolveSignupMethod(authUser),
|
|
57
|
+
user_id: uid,
|
|
58
|
+
},
|
|
59
|
+
attribution: buildAttributionContext(userRecord?.attribution),
|
|
60
|
+
identity: buildIdentity({
|
|
61
|
+
uid: uid,
|
|
62
|
+
user: userRecord,
|
|
63
|
+
// Auth's own record beats the doc for these two: on a fresh signup the
|
|
64
|
+
// doc's email came FROM it, and a phone-provider account has a number
|
|
65
|
+
// Auth holds and the doc's `personal.telephone` does not.
|
|
66
|
+
email: authUser.email,
|
|
67
|
+
telephone: authUser.phoneNumber,
|
|
68
|
+
request: request,
|
|
69
|
+
}),
|
|
70
|
+
trackingConsent: userRecord?.trackingConsent || null,
|
|
71
|
+
// The two providers that deduplicate on event_id (see the header) — GA4 is
|
|
72
|
+
// the browser half's to fire.
|
|
73
|
+
providers: ['meta', 'tiktok'],
|
|
74
|
+
eventId: `sign_up.${uid}`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Fire it (non-blocking, and never at its caller: a registration that already
|
|
80
|
+
* happened must not fail because an ad platform did).
|
|
81
|
+
*
|
|
82
|
+
* @param {object} options - `buildSignupFire`'s, plus the Manager and the ctx.
|
|
83
|
+
* @returns {void}
|
|
84
|
+
*/
|
|
85
|
+
function trackSignup({ Manager, ctx, authUser, userRecord, request }) {
|
|
86
|
+
try {
|
|
87
|
+
deliverConversion({
|
|
88
|
+
...buildSignupFire({ authUser, userRecord, request }),
|
|
89
|
+
ctx: ctx,
|
|
90
|
+
Manager: Manager,
|
|
91
|
+
});
|
|
92
|
+
} catch (e) {
|
|
93
|
+
ctx.error(`trackSignup: sign_up tracking failed for ${authUser?.uid}:`, e);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* How this account was created, in the same vocabulary the browser half sends:
|
|
99
|
+
* 'email' for a password signup, otherwise the provider's own name ('google',
|
|
100
|
+
* 'facebook', …) rather than its Firebase id ('google.com').
|
|
101
|
+
*
|
|
102
|
+
* @param {object} authUser - The Firebase Auth record.
|
|
103
|
+
* @returns {string} The method name.
|
|
104
|
+
*/
|
|
105
|
+
function resolveSignupMethod(authUser) {
|
|
106
|
+
const providerId = authUser?.providerData?.[0]?.providerId;
|
|
107
|
+
|
|
108
|
+
if (!providerId || providerId === 'password') {
|
|
109
|
+
return 'email';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return providerId.replace(/\.com$/, '');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = {
|
|
116
|
+
trackSignup,
|
|
117
|
+
// Exported for testing — the payload IS the contract with the browser half
|
|
118
|
+
buildSignupFire,
|
|
119
|
+
resolveSignupMethod,
|
|
120
|
+
};
|