@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.
Files changed (993) hide show
  1. package/LICENSE +98 -0
  2. package/README.md +1053 -0
  3. package/bin/omega +2 -0
  4. package/bin/omega-backend +2 -0
  5. package/bin/omg +2 -0
  6. package/cli.js +3 -0
  7. package/dist/cli/command-table.js +268 -0
  8. package/dist/cli/commands/auth.js +259 -0
  9. package/dist/cli/commands/base-command.js +451 -0
  10. package/dist/cli/commands/build.js +27 -0
  11. package/dist/cli/commands/clean.js +13 -0
  12. package/dist/cli/commands/clear.js +11 -0
  13. package/dist/cli/commands/cwd.js +9 -0
  14. package/dist/cli/commands/deploy.js +205 -0
  15. package/dist/cli/commands/emulator-orphans.js +440 -0
  16. package/dist/cli/commands/emulator.js +1829 -0
  17. package/dist/cli/commands/firebase-init.js +101 -0
  18. package/dist/cli/commands/firestore.js +261 -0
  19. package/dist/cli/commands/indexes.js +51 -0
  20. package/dist/cli/commands/install.js +151 -0
  21. package/dist/cli/commands/logs.js +358 -0
  22. package/dist/cli/commands/mcp.js +41 -0
  23. package/dist/cli/commands/migrate-markers.js +176 -0
  24. package/dist/cli/commands/migrate-rules.js +90 -0
  25. package/dist/cli/commands/migrate.js +59 -0
  26. package/dist/cli/commands/serve.js +208 -0
  27. package/dist/cli/commands/setup-tests/base-test.js +174 -0
  28. package/dist/cli/commands/setup-tests/emulator-config.js +109 -0
  29. package/dist/cli/commands/setup-tests/env-runtime-config-deprecated.js +47 -0
  30. package/dist/cli/commands/setup-tests/firebase-admin.js +49 -0
  31. package/dist/cli/commands/setup-tests/firebase-auth.js +26 -0
  32. package/dist/cli/commands/setup-tests/firebase-cli.js +26 -0
  33. package/dist/cli/commands/setup-tests/firebase-functions.js +49 -0
  34. package/dist/cli/commands/setup-tests/firestore-indexes-file.js +72 -0
  35. package/dist/cli/commands/setup-tests/firestore-indexes-in-json.js +20 -0
  36. package/dist/cli/commands/setup-tests/firestore-indexes-required.js +108 -0
  37. package/dist/cli/commands/setup-tests/firestore-indexes-synced.js +236 -0
  38. package/dist/cli/commands/setup-tests/firestore-rules-file.js +115 -0
  39. package/dist/cli/commands/setup-tests/firestore-rules-in-json.js +49 -0
  40. package/dist/cli/commands/setup-tests/functions-package.js +44 -0
  41. package/dist/cli/commands/setup-tests/gcloud-cli.js +26 -0
  42. package/dist/cli/commands/setup-tests/gitignore.js +122 -0
  43. package/dist/cli/commands/setup-tests/helpers/merge-line-files.js +28 -0
  44. package/dist/cli/commands/setup-tests/helpers/required-indexes.js +109 -0
  45. package/dist/cli/commands/setup-tests/helpers/seed-campaigns.js +246 -0
  46. package/dist/cli/commands/setup-tests/helpers.js +72 -0
  47. package/dist/cli/commands/setup-tests/hosting-folder.js +23 -0
  48. package/dist/cli/commands/setup-tests/hosting-rewrites.js +52 -0
  49. package/dist/cli/commands/setup-tests/index.js +111 -0
  50. package/dist/cli/commands/setup-tests/is-firebase-project.js +21 -0
  51. package/dist/cli/commands/setup-tests/java-installed.js +27 -0
  52. package/dist/cli/commands/setup-tests/legacy-tests-cleanup.js +43 -0
  53. package/dist/cli/commands/setup-tests/marketing-campaigns-seeded.js +230 -0
  54. package/dist/cli/commands/setup-tests/node-version.js +60 -0
  55. package/dist/cli/commands/setup-tests/npm-project-scripts.js +42 -0
  56. package/dist/cli/commands/setup-tests/nvmrc-version.js +36 -0
  57. package/dist/cli/commands/setup-tests/omega-backend.js +42 -0
  58. package/dist/cli/commands/setup-tests/omega-config.js +84 -0
  59. package/dist/cli/commands/setup-tests/project-directories.js +34 -0
  60. package/dist/cli/commands/setup-tests/project-id-consistency.js +201 -0
  61. package/dist/cli/commands/setup-tests/public-html-files.js +22 -0
  62. package/dist/cli/commands/setup-tests/realtime-rules-file.js +69 -0
  63. package/dist/cli/commands/setup-tests/realtime-rules-in-json.js +20 -0
  64. package/dist/cli/commands/setup-tests/remoteconfig-template-file.js +32 -0
  65. package/dist/cli/commands/setup-tests/remoteconfig-template-in-json.js +31 -0
  66. package/dist/cli/commands/setup-tests/service-account.js +86 -0
  67. package/dist/cli/commands/setup-tests/storage-lifecycle-policy.js +81 -0
  68. package/dist/cli/commands/setup-tests/storage-rules-file.js +32 -0
  69. package/dist/cli/commands/setup-tests/storage-rules-in-json.js +20 -0
  70. package/dist/cli/commands/stripe.js +14 -0
  71. package/dist/cli/commands/test-lanes/stripe-live.js +440 -0
  72. package/dist/cli/commands/test.js +976 -0
  73. package/dist/cli/commands/update.js +27 -0
  74. package/dist/cli/commands/version.js +10 -0
  75. package/dist/cli/commands/watch.js +196 -0
  76. package/dist/cli/flags.js +13 -0
  77. package/dist/cli/index.js +173 -0
  78. package/dist/cli/run.js +33 -0
  79. package/dist/cli/utils/attach-log-file.js +4 -0
  80. package/dist/cli/utils/compile-rules.js +1155 -0
  81. package/dist/cli/utils/ensure-target.js +314 -0
  82. package/dist/cli/utils/project-type.js +140 -0
  83. package/dist/cli/utils/public-files.js +49 -0
  84. package/dist/cli/utils/safe-install.js +4 -0
  85. package/dist/cli/utils/spawn-shell.js +94 -0
  86. package/dist/cli/utils/stage-functions.js +338 -0
  87. package/dist/cli/utils/stage-local-packages.js +210 -0
  88. package/dist/cli/utils/target-checks.js +161 -0
  89. package/dist/cli/utils/target.js +24 -0
  90. package/dist/cli/utils/ui.js +292 -0
  91. package/dist/defaults/AGENTS.md +125 -0
  92. package/dist/defaults/CHANGELOG.md +15 -0
  93. package/dist/defaults/CLAUDE.md +1 -0
  94. package/dist/defaults/_.gitignore +65 -0
  95. package/dist/defaults/docs/README.md +17 -0
  96. package/dist/defaults/test/README.md +65 -0
  97. package/dist/defaults/test/_init.js +14 -0
  98. package/dist/defaults/test/helpers/connect-trap.js +72 -0
  99. package/dist/defaults/test/unit/registration.test.js +143 -0
  100. package/dist/defaults/test/unit/rules-posture.test.js +101 -0
  101. package/dist/defaults/test/unit/socket-free.test.js +43 -0
  102. package/dist/manager/events/auth/before-create.js +89 -0
  103. package/dist/manager/events/auth/before-signin.js +76 -0
  104. package/dist/manager/events/auth/on-create.js +112 -0
  105. package/dist/manager/events/auth/on-delete.js +141 -0
  106. package/dist/manager/events/auth/utils.js +93 -0
  107. package/dist/manager/events/cron/daily/blog-auto-publisher.js +287 -0
  108. package/dist/manager/events/cron/daily/data-requests.js +57 -0
  109. package/dist/manager/events/cron/daily/expire-paypal-cancellations.js +191 -0
  110. package/dist/manager/events/cron/daily/marketing-prune.js +486 -0
  111. package/dist/manager/events/cron/daily/reset-usage.js +188 -0
  112. package/dist/manager/events/cron/daily/trial-lapse-sweep.js +355 -0
  113. package/dist/manager/events/cron/daily.js +3 -0
  114. package/dist/manager/events/cron/frequent/abandoned-carts.js +204 -0
  115. package/dist/manager/events/cron/frequent/email-queue.js +71 -0
  116. package/dist/manager/events/cron/frequent/marketing-campaigns.js +463 -0
  117. package/dist/manager/events/cron/frequent/retry-failed-webhooks.js +70 -0
  118. package/dist/manager/events/cron/frequent.js +3 -0
  119. package/dist/manager/events/cron/runner.js +64 -0
  120. package/dist/manager/events/firestore/notifications/on-write.js +123 -0
  121. package/dist/manager/events/firestore/payments-disputes/on-write.js +256 -0
  122. package/dist/manager/events/firestore/payments-disputes/providers/stripe.js +218 -0
  123. package/dist/manager/events/firestore/payments-disputes/providers/test.js +231 -0
  124. package/dist/manager/events/firestore/payments-webhooks/analytics.js +687 -0
  125. package/dist/manager/events/firestore/payments-webhooks/on-write.js +1224 -0
  126. package/dist/manager/events/firestore/payments-webhooks/transitions/index.js +395 -0
  127. package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-completed.js +58 -0
  128. package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-failed.js +28 -0
  129. package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-refunded.js +30 -0
  130. package/dist/manager/events/firestore/payments-webhooks/transitions/send-email.js +74 -0
  131. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/cancellation-removed.js +14 -0
  132. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/cancellation-requested.js +28 -0
  133. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/checkout-declined.js +18 -0
  134. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/new-subscription.js +67 -0
  135. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-failed.js +25 -0
  136. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-recovered.js +26 -0
  137. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-refunded.js +34 -0
  138. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/plan-changed.js +42 -0
  139. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/subscription-cancelled.js +33 -0
  140. package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/subscription-winback.js +17 -0
  141. package/dist/manager/functions/_legacy/actions/create-post-handler.js +188 -0
  142. package/dist/manager/functions/_legacy/actions/generate-uuid.js +63 -0
  143. package/dist/manager/functions/_legacy/actions/sign-up-handler.js +205 -0
  144. package/dist/manager/functions/_legacy/admin/create-post.js +207 -0
  145. package/dist/manager/functions/_legacy/admin/firestore-write.js +72 -0
  146. package/dist/manager/functions/_legacy/admin/get-stats.js +218 -0
  147. package/dist/manager/functions/_legacy/admin/query.js +198 -0
  148. package/dist/manager/functions/_legacy/admin/send-notification.js +206 -0
  149. package/dist/manager/functions/_legacy/template.js +33 -0
  150. package/dist/manager/functions/_legacy/test/authenticate.js +40 -0
  151. package/dist/manager/functions/_legacy/test/webhook.js +37 -0
  152. package/dist/manager/functions/wrappers/mailchimp/addToList.js +25 -0
  153. package/dist/manager/helpers/analytics.js +498 -0
  154. package/dist/manager/helpers/api-manager.js +313 -0
  155. package/dist/manager/helpers/backend-router.js +37 -0
  156. package/dist/manager/helpers/context/authenticate.js +215 -0
  157. package/dist/manager/helpers/context/client-info.js +91 -0
  158. package/dist/manager/helpers/context/index.js +228 -0
  159. package/dist/manager/helpers/context/logging.js +150 -0
  160. package/dist/manager/helpers/context/parse.js +160 -0
  161. package/dist/manager/helpers/context/respond.js +247 -0
  162. package/dist/manager/helpers/event-middleware.js +109 -0
  163. package/dist/manager/helpers/metadata.js +32 -0
  164. package/dist/manager/helpers/middleware.js +541 -0
  165. package/dist/manager/helpers/redact-secret.js +25 -0
  166. package/dist/manager/helpers/resolved-config.js +34 -0
  167. package/dist/manager/helpers/roles.js +69 -0
  168. package/dist/manager/helpers/safe-compare.js +31 -0
  169. package/dist/manager/helpers/schema-engine.js +314 -0
  170. package/dist/manager/helpers/schema-zod.js +203 -0
  171. package/dist/manager/helpers/settings.js +215 -0
  172. package/dist/manager/helpers/usage.js +541 -0
  173. package/dist/manager/helpers/user.js +57 -0
  174. package/dist/manager/helpers/utilities.js +565 -0
  175. package/dist/manager/index.js +1404 -0
  176. package/dist/manager/libraries/abandoned-cart-config.js +12 -0
  177. package/dist/manager/libraries/ai/index.js +321 -0
  178. package/dist/manager/libraries/ai/prompt.js +85 -0
  179. package/dist/manager/libraries/ai/providers/anthropic-format.js +297 -0
  180. package/dist/manager/libraries/ai/providers/anthropic.js +169 -0
  181. package/dist/manager/libraries/ai/providers/claude-code.js +183 -0
  182. package/dist/manager/libraries/ai/providers/openai.js +1272 -0
  183. package/dist/manager/libraries/ai/providers/test.js +257 -0
  184. package/dist/manager/libraries/ai/tokens.js +54 -0
  185. package/dist/manager/libraries/analytics/conversions.js +478 -0
  186. package/dist/manager/libraries/analytics/match-data.js +573 -0
  187. package/dist/manager/libraries/analytics/signup.js +120 -0
  188. package/dist/manager/libraries/auth-user.js +46 -0
  189. package/dist/manager/libraries/content/feed-parser.js +198 -0
  190. package/dist/manager/libraries/content/ghostii.js +191 -0
  191. package/dist/manager/libraries/content/source-resolver.js +629 -0
  192. package/dist/manager/libraries/email/constants.js +532 -0
  193. package/dist/manager/libraries/email/data/blocked-local-parts.json +55 -0
  194. package/dist/manager/libraries/email/data/blocked-local-patterns.js +14 -0
  195. package/dist/manager/libraries/email/data/corporate-domains.json +23 -0
  196. package/dist/manager/libraries/email/data/custom-disposable-domains.json +58 -0
  197. package/dist/manager/libraries/email/data/disposable-domains.json +8184 -0
  198. package/dist/manager/libraries/email/data/typo-domains.js +83 -0
  199. package/dist/manager/libraries/email/disposable-domains.js +92 -0
  200. package/dist/manager/libraries/email/generators/lib/filter.js +179 -0
  201. package/dist/manager/libraries/email/generators/lib/image-host.js +344 -0
  202. package/dist/manager/libraries/email/generators/lib/image-illustrator.js +154 -0
  203. package/dist/manager/libraries/email/generators/lib/markdown-renderer.js +294 -0
  204. package/dist/manager/libraries/email/generators/lib/mjml-template.js +120 -0
  205. package/dist/manager/libraries/email/generators/lib/structure.js +299 -0
  206. package/dist/manager/libraries/email/generators/lib/svg-illustrator.js +197 -0
  207. package/dist/manager/libraries/email/generators/lib/templates/base.js +229 -0
  208. package/dist/manager/libraries/email/generators/lib/templates/card.js +33 -0
  209. package/dist/manager/libraries/email/generators/lib/templates/classic-schema.js +59 -0
  210. package/dist/manager/libraries/email/generators/lib/templates/clean.js +82 -0
  211. package/dist/manager/libraries/email/generators/lib/templates/editorial/helpers.js +100 -0
  212. package/dist/manager/libraries/email/generators/lib/templates/editorial/index.js +318 -0
  213. package/dist/manager/libraries/email/generators/lib/templates/feedback.js +101 -0
  214. package/dist/manager/libraries/email/generators/lib/templates/field-report/helpers.js +138 -0
  215. package/dist/manager/libraries/email/generators/lib/templates/field-report/index.js +494 -0
  216. package/dist/manager/libraries/email/generators/lib/templates/index.js +47 -0
  217. package/dist/manager/libraries/email/generators/lib/templates/newsletter-shared.js +610 -0
  218. package/dist/manager/libraries/email/generators/lib/templates/order.js +461 -0
  219. package/dist/manager/libraries/email/generators/lib/templates/plain.js +83 -0
  220. package/dist/manager/libraries/email/generators/lib/templates/shared-campaign.js +64 -0
  221. package/dist/manager/libraries/email/generators/newsletter.js +899 -0
  222. package/dist/manager/libraries/email/index.js +146 -0
  223. package/dist/manager/libraries/email/marketing/index.js +754 -0
  224. package/dist/manager/libraries/email/prepare.js +365 -0
  225. package/dist/manager/libraries/email/providers/beehiiv.js +589 -0
  226. package/dist/manager/libraries/email/providers/sendgrid.js +845 -0
  227. package/dist/manager/libraries/email/transactional/index.js +510 -0
  228. package/dist/manager/libraries/email/utm.js +86 -0
  229. package/dist/manager/libraries/email/validation-provider-neverbounce.js +70 -0
  230. package/dist/manager/libraries/email/validation-provider-zerobounce.js +42 -0
  231. package/dist/manager/libraries/email/validation.js +255 -0
  232. package/dist/manager/libraries/env.js +198 -0
  233. package/dist/manager/libraries/infer-contact.js +101 -0
  234. package/dist/manager/libraries/load-provider.js +65 -0
  235. package/dist/manager/libraries/notification.js +256 -0
  236. package/dist/manager/libraries/openai.js +13 -0
  237. package/dist/manager/libraries/payment/discount-codes.js +204 -0
  238. package/dist/manager/libraries/payment/fetch-failure.js +56 -0
  239. package/dist/manager/libraries/payment/license.js +44 -0
  240. package/dist/manager/libraries/payment/order-id.js +57 -0
  241. package/dist/manager/libraries/payment/provider-errors.js +71 -0
  242. package/dist/manager/libraries/payment/providers/chargebee.js +817 -0
  243. package/dist/manager/libraries/payment/providers/coinbase.js +330 -0
  244. package/dist/manager/libraries/payment/providers/paypal.js +987 -0
  245. package/dist/manager/libraries/payment/providers/stripe.js +755 -0
  246. package/dist/manager/libraries/payment/providers/test.js +250 -0
  247. package/dist/manager/libraries/payment/refund-linkage.js +78 -0
  248. package/dist/manager/libraries/payment/refund-policy.js +113 -0
  249. package/dist/manager/libraries/payment/winback.js +55 -0
  250. package/dist/manager/libraries/prompts/infer-contact.md +78 -0
  251. package/dist/manager/libraries/rate-limits.js +17 -0
  252. package/dist/manager/libraries/recaptcha.js +58 -0
  253. package/dist/manager/libraries/user-doc.js +234 -0
  254. package/dist/manager/routes/admin/backup/post.js +106 -0
  255. package/dist/manager/routes/admin/cron/post.js +37 -0
  256. package/dist/manager/routes/admin/database/get.js +35 -0
  257. package/dist/manager/routes/admin/database/post.js +34 -0
  258. package/dist/manager/routes/admin/email/post.js +74 -0
  259. package/dist/manager/routes/admin/firestore/get.js +35 -0
  260. package/dist/manager/routes/admin/firestore/post.js +56 -0
  261. package/dist/manager/routes/admin/firestore/query/post.js +128 -0
  262. package/dist/manager/routes/admin/hook/post.js +104 -0
  263. package/dist/manager/routes/admin/infer-contact/post.js +35 -0
  264. package/dist/manager/routes/admin/notification/post.js +37 -0
  265. package/dist/manager/routes/admin/payment/post.js +56 -0
  266. package/dist/manager/routes/admin/post/deduplicate-image-alts.js +52 -0
  267. package/dist/manager/routes/admin/post/dispatch-deploy.js +36 -0
  268. package/dist/manager/routes/admin/post/post.js +487 -0
  269. package/dist/manager/routes/admin/post/put.js +146 -0
  270. package/dist/manager/routes/admin/post/templates/post.html +14 -0
  271. package/dist/manager/routes/admin/repo/content/post.js +106 -0
  272. package/dist/manager/routes/admin/stats/get.js +222 -0
  273. package/dist/manager/routes/admin/users/disable/post.js +50 -0
  274. package/dist/manager/routes/admin/users/list/get.js +110 -0
  275. package/dist/manager/routes/admin/users/sync/post.js +119 -0
  276. package/dist/manager/routes/brand/get.js +26 -0
  277. package/dist/manager/routes/content/post/get.js +110 -0
  278. package/dist/manager/routes/general/email/post.js +89 -0
  279. package/dist/manager/routes/general/email/templates/general/download-app-link.js +42 -0
  280. package/dist/manager/routes/general/uuid/post.js +31 -0
  281. package/dist/manager/routes/handler/post/post.js +142 -0
  282. package/dist/manager/routes/health/get.js +43 -0
  283. package/dist/manager/routes/index.js +11 -0
  284. package/dist/manager/routes/marketing/campaign/delete.js +45 -0
  285. package/dist/manager/routes/marketing/campaign/get.js +69 -0
  286. package/dist/manager/routes/marketing/campaign/post.js +124 -0
  287. package/dist/manager/routes/marketing/campaign/put.js +86 -0
  288. package/dist/manager/routes/marketing/campaign/utils.js +59 -0
  289. package/dist/manager/routes/marketing/contact/delete.js +100 -0
  290. package/dist/manager/routes/marketing/contact/post.js +149 -0
  291. package/dist/manager/routes/marketing/contact/put.js +37 -0
  292. package/dist/manager/routes/marketing/email-preferences/post.js +275 -0
  293. package/dist/manager/routes/marketing/webhook/forward/post.js +170 -0
  294. package/dist/manager/routes/marketing/webhook/post.js +123 -0
  295. package/dist/manager/routes/marketing/webhook/providers/beehiiv.js +197 -0
  296. package/dist/manager/routes/marketing/webhook/providers/sendgrid.js +194 -0
  297. package/dist/manager/routes/payments/cancel/_is-trialing.js +40 -0
  298. package/dist/manager/routes/payments/cancel/post.js +149 -0
  299. package/dist/manager/routes/payments/cancel/providers/chargebee.js +41 -0
  300. package/dist/manager/routes/payments/cancel/providers/paypal.js +56 -0
  301. package/dist/manager/routes/payments/cancel/providers/stripe.js +33 -0
  302. package/dist/manager/routes/payments/cancel/providers/test.js +118 -0
  303. package/dist/manager/routes/payments/discount/get.js +25 -0
  304. package/dist/manager/routes/payments/dispute-alert/post.js +117 -0
  305. package/dist/manager/routes/payments/dispute-alert/providers/chargeblast.js +55 -0
  306. package/dist/manager/routes/payments/intent/post.js +341 -0
  307. package/dist/manager/routes/payments/intent/providers/chargebee.js +197 -0
  308. package/dist/manager/routes/payments/intent/providers/coinbase.js +94 -0
  309. package/dist/manager/routes/payments/intent/providers/paypal.js +244 -0
  310. package/dist/manager/routes/payments/intent/providers/stripe.js +141 -0
  311. package/dist/manager/routes/payments/intent/providers/test.js +341 -0
  312. package/dist/manager/routes/payments/plan/post.js +147 -0
  313. package/dist/manager/routes/payments/plan/providers/chargebee.js +62 -0
  314. package/dist/manager/routes/payments/plan/providers/paypal.js +62 -0
  315. package/dist/manager/routes/payments/plan/providers/stripe.js +59 -0
  316. package/dist/manager/routes/payments/plan/providers/test.js +113 -0
  317. package/dist/manager/routes/payments/portal/post.js +113 -0
  318. package/dist/manager/routes/payments/portal/providers/chargebee.js +62 -0
  319. package/dist/manager/routes/payments/portal/providers/paypal.js +25 -0
  320. package/dist/manager/routes/payments/portal/providers/stripe.js +62 -0
  321. package/dist/manager/routes/payments/portal/providers/test.js +18 -0
  322. package/dist/manager/routes/payments/refund/post.js +207 -0
  323. package/dist/manager/routes/payments/refund/providers/chargebee.js +147 -0
  324. package/dist/manager/routes/payments/refund/providers/coinbase.js +40 -0
  325. package/dist/manager/routes/payments/refund/providers/paypal.js +239 -0
  326. package/dist/manager/routes/payments/refund/providers/stripe.js +160 -0
  327. package/dist/manager/routes/payments/refund/providers/test.js +204 -0
  328. package/dist/manager/routes/payments/trial-eligibility/get.js +29 -0
  329. package/dist/manager/routes/payments/uncancel/post.js +106 -0
  330. package/dist/manager/routes/payments/uncancel/providers/chargebee.js +30 -0
  331. package/dist/manager/routes/payments/uncancel/providers/paypal.js +25 -0
  332. package/dist/manager/routes/payments/uncancel/providers/stripe.js +27 -0
  333. package/dist/manager/routes/payments/uncancel/providers/test.js +114 -0
  334. package/dist/manager/routes/payments/webhook/post.js +157 -0
  335. package/dist/manager/routes/payments/webhook/providers/chargebee.js +218 -0
  336. package/dist/manager/routes/payments/webhook/providers/coinbase.js +91 -0
  337. package/dist/manager/routes/payments/webhook/providers/paypal.js +214 -0
  338. package/dist/manager/routes/payments/webhook/providers/stripe.js +182 -0
  339. package/dist/manager/routes/payments/webhook/providers/test.js +18 -0
  340. package/dist/manager/routes/payments/winback/post.js +276 -0
  341. package/dist/manager/routes/payments/winback/providers/chargebee.js +24 -0
  342. package/dist/manager/routes/payments/winback/providers/paypal.js +22 -0
  343. package/dist/manager/routes/payments/winback/providers/stripe.js +41 -0
  344. package/dist/manager/routes/payments/winback/providers/test.js +42 -0
  345. package/dist/manager/routes/restart/index.js +37 -0
  346. package/dist/manager/routes/special/electron-client/post.js +59 -0
  347. package/dist/manager/routes/test/authenticate/get.js +11 -0
  348. package/dist/manager/routes/test/health/get.js +8 -0
  349. package/dist/manager/routes/test/index.js +16 -0
  350. package/dist/manager/routes/test/lab/post.js +17 -0
  351. package/dist/manager/routes/test/redirect/get.js +27 -0
  352. package/dist/manager/routes/test/reset-account/post.js +79 -0
  353. package/dist/manager/routes/test/roster/get.js +40 -0
  354. package/dist/manager/routes/test/schema/post.js +20 -0
  355. package/dist/manager/routes/test/usage/post.js +44 -0
  356. package/dist/manager/routes/test/webhook/post.js +21 -0
  357. package/dist/manager/routes/user/api-keys/post.js +51 -0
  358. package/dist/manager/routes/user/connections/_context.js +194 -0
  359. package/dist/manager/routes/user/connections/_grant.js +247 -0
  360. package/dist/manager/routes/user/connections/_lease.js +184 -0
  361. package/dist/manager/routes/user/connections/_providers.js +191 -0
  362. package/dist/manager/routes/user/connections/_state.js +117 -0
  363. package/dist/manager/routes/user/connections/delete.js +55 -0
  364. package/dist/manager/routes/user/connections/get.js +167 -0
  365. package/dist/manager/routes/user/connections/post.js +370 -0
  366. package/dist/manager/routes/user/connections/providers/discord.js +41 -0
  367. package/dist/manager/routes/user/connections/providers/google.js +55 -0
  368. package/dist/manager/routes/user/connections/providers/kick.js +68 -0
  369. package/dist/manager/routes/user/connections/providers/spotify.js +40 -0
  370. package/dist/manager/routes/user/connections/providers/twitch.js +52 -0
  371. package/dist/manager/routes/user/data-request/delete.js +84 -0
  372. package/dist/manager/routes/user/data-request/get.js +229 -0
  373. package/dist/manager/routes/user/data-request/post.js +136 -0
  374. package/dist/manager/routes/user/delete.js +149 -0
  375. package/dist/manager/routes/user/feedback/post.js +81 -0
  376. package/dist/manager/routes/user/get.js +14 -0
  377. package/dist/manager/routes/user/orders/get.js +95 -0
  378. package/dist/manager/routes/user/sessions/delete.js +95 -0
  379. package/dist/manager/routes/user/sessions/get.js +40 -0
  380. package/dist/manager/routes/user/settings/validate/post.js +86 -0
  381. package/dist/manager/routes/user/signup/post.js +662 -0
  382. package/dist/manager/routes/user/subscription/get.js +77 -0
  383. package/dist/manager/routes/user/token/post.js +30 -0
  384. package/dist/manager/routes/verts/delete.js +43 -0
  385. package/dist/manager/routes/verts/get.js +49 -0
  386. package/dist/manager/routes/verts/post.js +61 -0
  387. package/dist/manager/routes/verts/put.js +75 -0
  388. package/dist/manager/routes/verts/redirect/get.js +36 -0
  389. package/dist/manager/routes/verts/serve/get.js +67 -0
  390. package/dist/manager/routes/verts/utils.js +436 -0
  391. package/dist/manager/schemas/admin/backup/post.js +8 -0
  392. package/dist/manager/schemas/admin/cron/post.js +8 -0
  393. package/dist/manager/schemas/admin/database/get.js +5 -0
  394. package/dist/manager/schemas/admin/database/post.js +6 -0
  395. package/dist/manager/schemas/admin/email/post.js +31 -0
  396. package/dist/manager/schemas/admin/firestore/get.js +5 -0
  397. package/dist/manager/schemas/admin/firestore/post.js +8 -0
  398. package/dist/manager/schemas/admin/firestore/query/post.js +5 -0
  399. package/dist/manager/schemas/admin/hook/post.js +8 -0
  400. package/dist/manager/schemas/admin/infer-contact/post.js +6 -0
  401. package/dist/manager/schemas/admin/notification/post.js +23 -0
  402. package/dist/manager/schemas/admin/payment/post.js +8 -0
  403. package/dist/manager/schemas/admin/post/post.js +23 -0
  404. package/dist/manager/schemas/admin/post/put.js +13 -0
  405. package/dist/manager/schemas/admin/repo/content/post.js +10 -0
  406. package/dist/manager/schemas/admin/stats/get.js +5 -0
  407. package/dist/manager/schemas/admin/users/disable/post.js +9 -0
  408. package/dist/manager/schemas/admin/users/list/get.js +10 -0
  409. package/dist/manager/schemas/admin/users/sync/post.js +7 -0
  410. package/dist/manager/schemas/brand/get.js +3 -0
  411. package/dist/manager/schemas/content/post/get.js +8 -0
  412. package/dist/manager/schemas/general/email/post.js +10 -0
  413. package/dist/manager/schemas/general/uuid/post.js +9 -0
  414. package/dist/manager/schemas/handler/post/post.js +13 -0
  415. package/dist/manager/schemas/health/get.js +3 -0
  416. package/dist/manager/schemas/marketing/campaign/delete.js +8 -0
  417. package/dist/manager/schemas/marketing/campaign/get.js +13 -0
  418. package/dist/manager/schemas/marketing/campaign/post.js +43 -0
  419. package/dist/manager/schemas/marketing/campaign/put.js +37 -0
  420. package/dist/manager/schemas/marketing/contact/delete.js +8 -0
  421. package/dist/manager/schemas/marketing/contact/post.js +14 -0
  422. package/dist/manager/schemas/marketing/contact/put.js +8 -0
  423. package/dist/manager/schemas/marketing/email-preferences/post.js +15 -0
  424. package/dist/manager/schemas/marketing/webhook/forward/post.js +8 -0
  425. package/dist/manager/schemas/marketing/webhook/post.js +7 -0
  426. package/dist/manager/schemas/payments/cancel/post.js +15 -0
  427. package/dist/manager/schemas/payments/discount/get.js +8 -0
  428. package/dist/manager/schemas/payments/dispute-alert/post.js +6 -0
  429. package/dist/manager/schemas/payments/intent/post.js +28 -0
  430. package/dist/manager/schemas/payments/plan/post.js +11 -0
  431. package/dist/manager/schemas/payments/portal/post.js +12 -0
  432. package/dist/manager/schemas/payments/refund/post.js +14 -0
  433. package/dist/manager/schemas/payments/trial-eligibility/get.js +7 -0
  434. package/dist/manager/schemas/payments/uncancel/post.js +9 -0
  435. package/dist/manager/schemas/payments/webhook/post.js +6 -0
  436. package/dist/manager/schemas/payments/winback/post.js +12 -0
  437. package/dist/manager/schemas/restart/index.js +5 -0
  438. package/dist/manager/schemas/special/electron-client/post.js +11 -0
  439. package/dist/manager/schemas/test/authenticate/get.js +3 -0
  440. package/dist/manager/schemas/test/health/get.js +3 -0
  441. package/dist/manager/schemas/test/index.js +5 -0
  442. package/dist/manager/schemas/test/lab/post.js +3 -0
  443. package/dist/manager/schemas/test/redirect/get.js +7 -0
  444. package/dist/manager/schemas/test/reset-account/post.js +3 -0
  445. package/dist/manager/schemas/test/roster/get.js +3 -0
  446. package/dist/manager/schemas/test/schema/post.js +70 -0
  447. package/dist/manager/schemas/test/usage/post.js +8 -0
  448. package/dist/manager/schemas/test/webhook/post.js +7 -0
  449. package/dist/manager/schemas/user/api-keys/post.js +6 -0
  450. package/dist/manager/schemas/user/connections/delete.js +8 -0
  451. package/dist/manager/schemas/user/connections/get.js +21 -0
  452. package/dist/manager/schemas/user/connections/post.js +12 -0
  453. package/dist/manager/schemas/user/data-request/delete.js +3 -0
  454. package/dist/manager/schemas/user/data-request/get.js +5 -0
  455. package/dist/manager/schemas/user/data-request/post.js +6 -0
  456. package/dist/manager/schemas/user/delete.js +6 -0
  457. package/dist/manager/schemas/user/feedback/post.js +8 -0
  458. package/dist/manager/schemas/user/get.js +3 -0
  459. package/dist/manager/schemas/user/orders/get.js +6 -0
  460. package/dist/manager/schemas/user/sessions/delete.js +6 -0
  461. package/dist/manager/schemas/user/sessions/get.js +6 -0
  462. package/dist/manager/schemas/user/settings/validate/post.js +8 -0
  463. package/dist/manager/schemas/user/signup/post.js +27 -0
  464. package/dist/manager/schemas/user/subscription/get.js +5 -0
  465. package/dist/manager/schemas/user/token/post.js +5 -0
  466. package/dist/manager/schemas/verts/delete.js +8 -0
  467. package/dist/manager/schemas/verts/get.js +9 -0
  468. package/dist/manager/schemas/verts/post.js +23 -0
  469. package/dist/manager/schemas/verts/put.js +20 -0
  470. package/dist/manager/schemas/verts/redirect/get.js +10 -0
  471. package/dist/manager/schemas/verts/serve/get.js +14 -0
  472. package/dist/manager/server-manager.js +69 -0
  473. package/dist/mcp/client.js +98 -0
  474. package/dist/mcp/handler.js +521 -0
  475. package/dist/mcp/index.js +157 -0
  476. package/dist/mcp/tools.js +555 -0
  477. package/dist/mcp/utils.js +108 -0
  478. package/dist/omega-bin.js +6 -0
  479. package/dist/require.js +3 -0
  480. package/dist/test/fixtures/firebase-project/.firebaserc +5 -0
  481. package/dist/test/fixtures/firebase-project/config/omega.json5 +131 -0
  482. package/dist/test/fixtures/firebase-project/database.rules.json +6 -0
  483. package/dist/test/fixtures/firebase-project/firebase.json +49 -0
  484. package/dist/test/fixtures/firebase-project/firestore.indexes.json +4 -0
  485. package/dist/test/fixtures/firebase-project/package.json +14 -0
  486. package/dist/test/fixtures/firebase-project/src/index.js +11 -0
  487. package/dist/test/fixtures/firebase-project/storage.rules +8 -0
  488. package/dist/test/parse-audit.js +25 -0
  489. package/dist/test/run-tests.js +90 -0
  490. package/dist/test/runner.js +982 -0
  491. package/dist/test/seed.js +242 -0
  492. package/dist/test/test-accounts.js +2660 -0
  493. package/dist/test/utils/assertions.js +189 -0
  494. package/dist/test/utils/email-capture.js +252 -0
  495. package/dist/test/utils/extended-mode-warning.js +11 -0
  496. package/dist/test/utils/firestore-rules-client.js +277 -0
  497. package/dist/test/utils/http-client.js +228 -0
  498. package/dist/test/utils/test-mode-file.js +192 -0
  499. package/dist/utils/merge-line-files.js +6 -0
  500. package/dist/utils/scaffold-defaults.js +71 -0
  501. package/dist/utils/test-lanes.js +62 -0
  502. package/dist/vendor/account/engine.js +182 -0
  503. package/dist/vendor/account/features.js +220 -0
  504. package/dist/vendor/account/index.js +53 -0
  505. package/dist/vendor/account/schema.js +272 -0
  506. package/dist/vendor/account/subscription.js +38 -0
  507. package/dist/vendor/analytics/adapters/ga4.js +26 -0
  508. package/dist/vendor/analytics/adapters/meta.js +26 -0
  509. package/dist/vendor/analytics/adapters/resolve.js +130 -0
  510. package/dist/vendor/analytics/adapters/tiktok.js +27 -0
  511. package/dist/vendor/analytics/catalog.js +908 -0
  512. package/dist/vendor/analytics/identity.js +136 -0
  513. package/dist/vendor/config/company.js +31 -0
  514. package/dist/vendor/config/defaults.js +173 -0
  515. package/dist/vendor/config/demo.js +18 -0
  516. package/dist/vendor/config/desktop-artifacts.js +110 -0
  517. package/dist/vendor/config/edit.js +769 -0
  518. package/dist/vendor/config/env-delivery.js +145 -0
  519. package/dist/vendor/config/env-rules.js +93 -0
  520. package/dist/vendor/config/env-schema.js +1078 -0
  521. package/dist/vendor/config/env.js +445 -0
  522. package/dist/vendor/config/hooks.js +97 -0
  523. package/dist/vendor/config/index.js +237 -0
  524. package/dist/vendor/config/instances.js +208 -0
  525. package/dist/vendor/config/load.js +490 -0
  526. package/dist/vendor/config/merge.js +68 -0
  527. package/dist/vendor/config/order.js +139 -0
  528. package/dist/vendor/config/ports.js +374 -0
  529. package/dist/vendor/config/providers.js +32 -0
  530. package/dist/vendor/config/repo.js +142 -0
  531. package/dist/vendor/config/retired-keys.js +430 -0
  532. package/dist/vendor/config/schema.js +1610 -0
  533. package/dist/vendor/config/secrets.js +50 -0
  534. package/dist/vendor/config/seed.js +34 -0
  535. package/dist/vendor/config/site-global.js +205 -0
  536. package/dist/vendor/config/validate.js +554 -0
  537. package/dist/vendor/config/winback.js +61 -0
  538. package/dist/vendor/devkit/attach-log-file.js +262 -0
  539. package/dist/vendor/devkit/bare-requires.js +153 -0
  540. package/dist/vendor/devkit/command-path.js +46 -0
  541. package/dist/vendor/devkit/defaults-engine.js +372 -0
  542. package/dist/vendor/devkit/deploy-record.js +180 -0
  543. package/dist/vendor/devkit/deploy.js +286 -0
  544. package/dist/vendor/devkit/license.js +155 -0
  545. package/dist/vendor/devkit/local-https.js +360 -0
  546. package/dist/vendor/devkit/local.js +1905 -0
  547. package/dist/vendor/devkit/logger.js +128 -0
  548. package/dist/vendor/devkit/merge-line-files.js +296 -0
  549. package/dist/vendor/devkit/npm-registry.js +52 -0
  550. package/dist/vendor/devkit/omega-bin.js +345 -0
  551. package/dist/vendor/devkit/parse-audit.js +74 -0
  552. package/dist/vendor/devkit/safe-install.js +18 -0
  553. package/dist/vendor/devkit/scaffold-guard.js +96 -0
  554. package/dist/vendor/devkit/stop-signals.js +28 -0
  555. package/dist/vendor/devkit/test/assert.js +120 -0
  556. package/dist/vendor/devkit/test/define-cases.js +104 -0
  557. package/dist/vendor/devkit/test/runner-core.js +554 -0
  558. package/dist/vendor/devkit/test/scope.js +162 -0
  559. package/dist/vendor/devkit/update.js +569 -0
  560. package/dist/vendor/monitoring/core.js +180 -0
  561. package/dist/vendor/monitoring/env.js +49 -0
  562. package/dist/vendor/monitoring/logger.js +39 -0
  563. package/dist/vendor/monitoring/node.js +72 -0
  564. package/docs/admin-post-route.md +57 -0
  565. package/docs/ai-library.md +171 -0
  566. package/docs/architecture.md +62 -0
  567. package/docs/audit.md +70 -0
  568. package/docs/auth-hooks.md +74 -0
  569. package/docs/build-system.md +65 -0
  570. package/docs/cdp-debugging.md +29 -0
  571. package/docs/cli-firestore-auth.md +85 -0
  572. package/docs/cli-logs.md +67 -0
  573. package/docs/cli-output.md +146 -0
  574. package/docs/code-patterns.md +77 -0
  575. package/docs/common-mistakes.md +12 -0
  576. package/docs/common-operations.md +60 -0
  577. package/docs/connections.md +212 -0
  578. package/docs/consent.md +362 -0
  579. package/docs/directory-structure.md +150 -0
  580. package/docs/email-system.md +459 -0
  581. package/docs/environment-detection.md +93 -0
  582. package/docs/file-naming.md +10 -0
  583. package/docs/firestore.md +134 -0
  584. package/docs/ghostii.md +240 -0
  585. package/docs/index.md +299 -0
  586. package/docs/key-files.md +37 -0
  587. package/docs/logging.md +60 -0
  588. package/docs/marketing-campaigns.md +407 -0
  589. package/docs/marketing-fields.md +25 -0
  590. package/docs/mcp.md +222 -0
  591. package/docs/migration.md +129 -0
  592. package/docs/payment-system.md +856 -0
  593. package/docs/paypal-sandbox-qa.md +105 -0
  594. package/docs/response-headers.md +9 -0
  595. package/docs/routes.md +211 -0
  596. package/docs/sanitization.md +71 -0
  597. package/docs/schemas.md +163 -0
  598. package/docs/shared/agent-docs.md +89 -0
  599. package/docs/shared/analytics.md +612 -0
  600. package/docs/shared/brands.md +51 -0
  601. package/docs/shared/breaking-changes.md +497 -0
  602. package/docs/shared/config.md +1387 -0
  603. package/docs/shared/deploys.md +215 -0
  604. package/docs/shared/icons.md +201 -0
  605. package/docs/shared/local-dev.md +147 -0
  606. package/docs/shared/logging.md +202 -0
  607. package/docs/shared/monitoring.md +153 -0
  608. package/docs/shared/publishing.md +183 -0
  609. package/docs/shared/rulings.md +34 -0
  610. package/docs/shared/testing.md +147 -0
  611. package/docs/shared/theming.md +604 -0
  612. package/docs/shared/translation.md +291 -0
  613. package/docs/shared/updates.md +61 -0
  614. package/docs/stripe-webhook-forwarding.md +20 -0
  615. package/docs/test-boot-layer.md +67 -0
  616. package/docs/test-framework.md +583 -0
  617. package/docs/usage-rate-limiting.md +121 -0
  618. package/docs/verts.md +29 -0
  619. package/package.json +143 -0
  620. package/templates/config/omega.json5 +322 -0
  621. package/templates/database.rules.json +82 -0
  622. package/templates/firebase.json +67 -0
  623. package/templates/firestore.framework.rules +191 -0
  624. package/templates/firestore.indexes.json +4 -0
  625. package/templates/firestore.rules +59 -0
  626. package/templates/index.js +12 -0
  627. package/templates/public/404.html +26 -0
  628. package/templates/public/index.html +24 -0
  629. package/templates/remoteconfig.template.json +1 -0
  630. package/templates/storage-lifecycle-config-1-day.json +9 -0
  631. package/templates/storage-lifecycle-config-30-days.json +9 -0
  632. package/templates/storage.rules +11 -0
  633. package/test/_init/accounts-validation.js +58 -0
  634. package/test/ai/tools-live.test.js +171 -0
  635. package/test/analytics/conversion-delivery.test.js +1013 -0
  636. package/test/analytics/match-normalization.test.js +238 -0
  637. package/test/analytics/signup-conversion.test.js +135 -0
  638. package/test/boot/cli-dispatch.test.js +142 -0
  639. package/test/boot/defaults-scaffold.test.js +248 -0
  640. package/test/boot/deploy-staging.test.js +446 -0
  641. package/test/boot/disposable-domains.test.js +154 -0
  642. package/test/boot/emulator-boots.test.js +39 -0
  643. package/test/boot/emulator-port-preflight.test.js +126 -0
  644. package/test/boot/emulator-ready-timeout.test.js +46 -0
  645. package/test/boot/project-id-refresh.test.js +73 -0
  646. package/test/boot/suite-portability.test.js +278 -0
  647. package/test/boot/update-command.test.js +63 -0
  648. package/test/cli/cross-platform.test.js +168 -0
  649. package/test/cli/custom-project-type.test.js +426 -0
  650. package/test/cli/deploy-license-env.test.js +100 -0
  651. package/test/cli/emulator-adoption.test.js +254 -0
  652. package/test/cli/emulator-orphans.test.js +658 -0
  653. package/test/cli/emulator-ownership.test.js +177 -0
  654. package/test/cli/emulator-port-retry.test.js +395 -0
  655. package/test/cli/emulator-shutdown.test.js +788 -0
  656. package/test/cli/emulator-stale-reap.test.js +574 -0
  657. package/test/cli/ensure-target.test.js +325 -0
  658. package/test/cli/flags.test.js +64 -0
  659. package/test/cli/https-trust.test.js +38 -0
  660. package/test/cli/install-update-dispatch.test.js +47 -0
  661. package/test/cli/lane-environments.test.js +159 -0
  662. package/test/cli/marketing-campaigns-seeded.test.js +194 -0
  663. package/test/cli/migrate-bare-requires.test.js +128 -0
  664. package/test/cli/migrate-markers.test.js +530 -0
  665. package/test/cli/required-indexes.test.js +64 -0
  666. package/test/cli/rules-compile.test.js +622 -0
  667. package/test/cli/rules-migration-deferral.test.js +259 -0
  668. package/test/cli/rules-version.test.js +104 -0
  669. package/test/cli/setup-load-files.test.js +66 -0
  670. package/test/cli/setup-offline-mode.test.js +276 -0
  671. package/test/cli/setup-retired.test.js +64 -0
  672. package/test/cli/setup-shared-project-indexes.test.js +262 -0
  673. package/test/cli/setup-tests-requires.test.js +45 -0
  674. package/test/cli/stage-env-compose.test.js +316 -0
  675. package/test/cli/stripe-live-lane.test.js +303 -0
  676. package/test/cli/target.test.js +182 -0
  677. package/test/cli/templates.test.js +66 -0
  678. package/test/cli/test-runner-env.test.js +115 -0
  679. package/test/cli/test-stack-shutdown.test.js +275 -0
  680. package/test/cli/test-target-no-match.test.js +128 -0
  681. package/test/cli/verb-logs.test.js +118 -0
  682. package/test/cli/version-dispatch.test.js +39 -0
  683. package/test/content/blog-generate.test.js +164 -0
  684. package/test/email/campaign-config-fault.test.js +376 -0
  685. package/test/email/campaign-cron-pipeline.test.js +536 -0
  686. package/test/email/campaign-send.test.js +47 -0
  687. package/test/email/consent-lifecycle.test.js +258 -0
  688. package/test/email/content-html-policy.test.js +270 -0
  689. package/test/email/feedback-and-plain-send.test.js +54 -0
  690. package/test/email/fixtures/clean.json +30 -0
  691. package/test/email/fixtures/editorial.json +30 -0
  692. package/test/email/fixtures/field-report.json +53 -0
  693. package/test/email/identity.test.js +321 -0
  694. package/test/email/marketing/consent-gate.test.js +265 -0
  695. package/test/email/marketing/custom-fields-catalog.test.js +259 -0
  696. package/test/email/marketing/prune-per-provider.test.js +762 -0
  697. package/test/email/marketing/remove-log-privacy.test.js +225 -0
  698. package/test/email/marketing-lifecycle.test.js +139 -0
  699. package/test/email/newsletter-generate.test.js +853 -0
  700. package/test/email/newsletter-svg-tokens.test.js +51 -0
  701. package/test/email/newsletter-templates.test.js +492 -0
  702. package/test/email/order-one-time-cta.test.js +97 -0
  703. package/test/email/render-content.test.js +248 -0
  704. package/test/email/safe-url.test.js +0 -0
  705. package/test/email/sanitize-images.test.js +66 -0
  706. package/test/email/send-log-privacy.test.js +107 -0
  707. package/test/email/templates.test.js +288 -0
  708. package/test/email/testing-capture.test.js +260 -0
  709. package/test/email/transactional-send.test.js +36 -0
  710. package/test/email/transactional.test.js +562 -0
  711. package/test/email/unsubscribe-groups.test.js +155 -0
  712. package/test/email/unsubscribe-key.test.js +91 -0
  713. package/test/email/validation-cases.test.js +152 -0
  714. package/test/email/validation.test.js +746 -0
  715. package/test/events/auth-delete-conversion.test.js +138 -0
  716. package/test/events/auth-delete-race.test.js +211 -0
  717. package/test/events/auth-on-create-log.test.js +164 -0
  718. package/test/events/auth-signup-conversion.test.js +141 -0
  719. package/test/events/auth-signup-limit.test.js +142 -0
  720. package/test/events/auth-trigger-log-privacy.test.js +256 -0
  721. package/test/events/cron-job-doc-shape.test.js +101 -0
  722. package/test/events/cron-reset-usage.test.js +116 -0
  723. package/test/events/notification-conversion.test.js +182 -0
  724. package/test/events/payments/_webhook-harness.js +307 -0
  725. package/test/events/payments/abandoned-cart-activity.test.js +135 -0
  726. package/test/events/payments/analytics-payment-events.test.js +945 -0
  727. package/test/events/payments/dispute-email-status.test.js +55 -0
  728. package/test/events/payments/journey-payments-abandoned.test.js +126 -0
  729. package/test/events/payments/journey-payments-cancel-endpoint.test.js +102 -0
  730. package/test/events/payments/journey-payments-cancel-no-order.test.js +76 -0
  731. package/test/events/payments/journey-payments-cancel.test.js +184 -0
  732. package/test/events/payments/journey-payments-decline.test.js +225 -0
  733. package/test/events/payments/journey-payments-discount.test.js +91 -0
  734. package/test/events/payments/journey-payments-dispute.test.js +190 -0
  735. package/test/events/payments/journey-payments-failure.test.js +148 -0
  736. package/test/events/payments/journey-payments-legacy-product.test.js +151 -0
  737. package/test/events/payments/journey-payments-one-time-decline.test.js +127 -0
  738. package/test/events/payments/journey-payments-one-time-failure.test.js +113 -0
  739. package/test/events/payments/journey-payments-one-time-refund.test.js +186 -0
  740. package/test/events/payments/journey-payments-one-time.test.js +175 -0
  741. package/test/events/payments/journey-payments-plan-change.test.js +146 -0
  742. package/test/events/payments/journey-payments-plan-switch-trial.test.js +161 -0
  743. package/test/events/payments/journey-payments-plan-switch.test.js +182 -0
  744. package/test/events/payments/journey-payments-refund-no-order.test.js +76 -0
  745. package/test/events/payments/journey-payments-refund-webhook.test.js +225 -0
  746. package/test/events/payments/journey-payments-suspend.test.js +183 -0
  747. package/test/events/payments/journey-payments-trial-cancel.test.js +132 -0
  748. package/test/events/payments/journey-payments-trial.test.js +173 -0
  749. package/test/events/payments/journey-payments-uid-resolution.test.js +134 -0
  750. package/test/events/payments/journey-payments-uncancel.test.js +157 -0
  751. package/test/events/payments/journey-payments-upgrade.test.js +137 -0
  752. package/test/events/payments/journey-payments-winback-decline.test.js +171 -0
  753. package/test/events/payments/journey-payments-winback.test.js +195 -0
  754. package/test/events/payments/paypal-expiry-cron.test.js +166 -0
  755. package/test/events/payments/purchase-failed-handler.test.js +80 -0
  756. package/test/events/payments/purchase-refunded-handler.test.js +108 -0
  757. package/test/events/payments/test-processor-doc-shape.test.js +162 -0
  758. package/test/events/payments/transition-order-emails.test.js +185 -0
  759. package/test/events/payments/transition-promo-lines.test.js +192 -0
  760. package/test/events/payments/transitions-detect.test.js +767 -0
  761. package/test/events/payments/trial-lapse-sweep-staleness.test.js +173 -0
  762. package/test/events/payments/trial-lapse-sweep.test.js +359 -0
  763. package/test/events/payments/webhook-atomic-writes.test.js +69 -0
  764. package/test/events/payments/webhook-chargebee-unreachable.test.js +106 -0
  765. package/test/events/payments/webhook-discount-clear.test.js +189 -0
  766. package/test/events/payments/webhook-failure-intent.test.js +93 -0
  767. package/test/events/payments/webhook-hosted-page-uid-trust.test.js +212 -0
  768. package/test/events/payments/webhook-ordering.test.js +326 -0
  769. package/test/events/payments/webhook-provider-lookup-trust.test.js +206 -0
  770. package/test/events/payments/webhook-refund-amount-trust.test.js +223 -0
  771. package/test/events/payments/webhook-refund-envelope-shape.test.js +148 -0
  772. package/test/events/payments/webhook-refund-linkage-trust.test.js +404 -0
  773. package/test/events/payments/webhook-refund-transaction-fallback.test.js +184 -0
  774. package/test/events/payments/webhook-refund-without-order.test.js +170 -0
  775. package/test/events/payments/webhook-refusal-reporting.test.js +194 -0
  776. package/test/events/payments/webhook-refused-intent.test.js +142 -0
  777. package/test/events/payments/webhook-retry-sweep.test.js +252 -0
  778. package/test/events/payments/webhook-transition-claim.test.js +389 -0
  779. package/test/events/payments/webhook-uid-trust.test.js +203 -0
  780. package/test/events/payments/webhook-user-without-auth.test.js +161 -0
  781. package/test/fixtures/chargebee/invoice-one-time.json +27 -0
  782. package/test/fixtures/chargebee/subscription-active.json +44 -0
  783. package/test/fixtures/chargebee/subscription-cancelled.json +42 -0
  784. package/test/fixtures/chargebee/subscription-in-trial.json +41 -0
  785. package/test/fixtures/chargebee/subscription-legacy-plan.json +41 -0
  786. package/test/fixtures/chargebee/subscription-non-renewing.json +41 -0
  787. package/test/fixtures/chargebee/subscription-paused.json +42 -0
  788. package/test/fixtures/chargebee/webhook-payment-failed.json +51 -0
  789. package/test/fixtures/chargebee/webhook-subscription-created.json +47 -0
  790. package/test/fixtures/coinbase/charge-confirmed.json +50 -0
  791. package/test/fixtures/coinbase/charge-failed.json +34 -0
  792. package/test/fixtures/coinbase/charge-pending.json +34 -0
  793. package/test/fixtures/migrate/ported-route.js.txt +11 -0
  794. package/test/fixtures/paypal/capture-completed.json +51 -0
  795. package/test/fixtures/paypal/capture-refunded.json +43 -0
  796. package/test/fixtures/paypal/order-approved.json +62 -0
  797. package/test/fixtures/paypal/order-completed.json +110 -0
  798. package/test/fixtures/paypal/sale-refunded.json +38 -0
  799. package/test/fixtures/paypal/subscription-active.json +76 -0
  800. package/test/fixtures/paypal/subscription-cancelled.json +50 -0
  801. package/test/fixtures/paypal/subscription-suspended.json +65 -0
  802. package/test/fixtures/stripe/checkout-session-completed.json +130 -0
  803. package/test/fixtures/stripe/invoice-payment-failed.json +148 -0
  804. package/test/fixtures/stripe/invoice-subscription-payment-failed.json +28 -0
  805. package/test/fixtures/stripe/invoice-subscription-payment-succeeded.json +28 -0
  806. package/test/fixtures/stripe/subscription-active.json +161 -0
  807. package/test/fixtures/stripe/subscription-canceled.json +161 -0
  808. package/test/fixtures/stripe/subscription-trialing.json +161 -0
  809. package/test/helpers/_shared-config.js +15 -0
  810. package/test/helpers/ai-request-payload.test.js +619 -0
  811. package/test/helpers/ai-schema-resolve.test.js +125 -0
  812. package/test/helpers/ai-test-provider.test.js +227 -0
  813. package/test/helpers/ai-token-accounting.test.js +150 -0
  814. package/test/helpers/ai-tools-format.test.js +384 -0
  815. package/test/helpers/analytics-no-id-notice.test.js +146 -0
  816. package/test/helpers/analytics-user-data.test.js +194 -0
  817. package/test/helpers/api-manager.test.js +311 -0
  818. package/test/helpers/backend-router.test.js +136 -0
  819. package/test/helpers/content/blog-auto-publisher.test.js +482 -0
  820. package/test/helpers/content/feed-parser.test.js +529 -0
  821. package/test/helpers/content/ghostii-blocks.test.js +135 -0
  822. package/test/helpers/content/ghostii-feed-integration.test.js +405 -0
  823. package/test/helpers/content/ghostii-write-article.test.js +244 -0
  824. package/test/helpers/dev-only-routes.test.js +225 -0
  825. package/test/helpers/env-reader.test.js +362 -0
  826. package/test/helpers/environment.test.js +263 -0
  827. package/test/helpers/event-middleware.test.js +407 -0
  828. package/test/helpers/infer-contact.test.js +157 -0
  829. package/test/helpers/lane-url.test.js +90 -0
  830. package/test/helpers/merge-line-files.test.js +272 -0
  831. package/test/helpers/metadata.test.js +122 -0
  832. package/test/helpers/middleware-request-log.test.js +134 -0
  833. package/test/helpers/middleware-user-log.test.js +124 -0
  834. package/test/helpers/payment/chargebee/parse-webhook.test.js +490 -0
  835. package/test/helpers/payment/chargebee/refund-details.test.js +198 -0
  836. package/test/helpers/payment/chargebee/to-unified-one-time.test.js +148 -0
  837. package/test/helpers/payment/chargebee/to-unified-subscription.test.js +649 -0
  838. package/test/helpers/payment/coinbase/create-intent.test.js +247 -0
  839. package/test/helpers/payment/coinbase/parse-webhook.test.js +195 -0
  840. package/test/helpers/payment/coinbase/refund-unsupported.test.js +141 -0
  841. package/test/helpers/payment/coinbase/to-unified-one-time.test.js +201 -0
  842. package/test/helpers/payment/discount-codes.test.js +141 -0
  843. package/test/helpers/payment/extract-resource.test.js +113 -0
  844. package/test/helpers/payment/fetch-failure.test.js +215 -0
  845. package/test/helpers/payment/license-gate.test.js +108 -0
  846. package/test/helpers/payment/order-id.test.js +99 -0
  847. package/test/helpers/payment/paypal/create-intent.test.js +382 -0
  848. package/test/helpers/payment/paypal/fetch-capture.test.js +123 -0
  849. package/test/helpers/payment/paypal/fetch-sale.test.js +183 -0
  850. package/test/helpers/payment/paypal/parse-webhook.test.js +678 -0
  851. package/test/helpers/payment/paypal/refund-details.test.js +202 -0
  852. package/test/helpers/payment/paypal/resolve-plan-id.test.js +108 -0
  853. package/test/helpers/payment/paypal/switch-plan.test.js +92 -0
  854. package/test/helpers/payment/paypal/to-unified-one-time.test.js +383 -0
  855. package/test/helpers/payment/paypal/to-unified-subscription.test.js +884 -0
  856. package/test/helpers/payment/stripe/fetch-charge.test.js +147 -0
  857. package/test/helpers/payment/stripe/parse-webhook.test.js +448 -0
  858. package/test/helpers/payment/stripe/refund-details.test.js +147 -0
  859. package/test/helpers/payment/stripe/to-unified-one-time.test.js +307 -0
  860. package/test/helpers/payment/stripe/to-unified-subscription.test.js +709 -0
  861. package/test/helpers/persona-domain.test.js +87 -0
  862. package/test/helpers/recaptcha.test.js +166 -0
  863. package/test/helpers/resolved-config.test.js +106 -0
  864. package/test/helpers/response-log-redaction.test.js +262 -0
  865. package/test/helpers/roles.test.js +155 -0
  866. package/test/helpers/route-context-debug-gate.test.js +118 -0
  867. package/test/helpers/route-context-logging.test.js +214 -0
  868. package/test/helpers/route-context.test.js +129 -0
  869. package/test/helpers/safe-compare.test.js +114 -0
  870. package/test/helpers/sanitize.test.js +223 -0
  871. package/test/helpers/schema-engine.test.js +537 -0
  872. package/test/helpers/schema-zod.test.js +554 -0
  873. package/test/helpers/seed-accounts-load.test.js +163 -0
  874. package/test/helpers/seed-google-personas.test.js +114 -0
  875. package/test/helpers/seeded-personas.test.js +823 -0
  876. package/test/helpers/settings.test.js +292 -0
  877. package/test/helpers/setup-engines-pin.test.js +68 -0
  878. package/test/helpers/setup-manifest-sync.test.js +116 -0
  879. package/test/helpers/slugify.test.js +395 -0
  880. package/test/helpers/storage.test.js +195 -0
  881. package/test/helpers/test-banner-latch.test.js +139 -0
  882. package/test/helpers/usage-consume.test.js +460 -0
  883. package/test/helpers/usage-log-privacy.test.js +121 -0
  884. package/test/helpers/user-doc-heal.test.js +540 -0
  885. package/test/helpers/user.test.js +771 -0
  886. package/test/helpers/webhook-forward.test.js +419 -0
  887. package/test/helpers/wipe-auth-project.test.js +143 -0
  888. package/test/mcp/discovery.test.js +52 -0
  889. package/test/mcp/oauth.test.js +160 -0
  890. package/test/mcp/protocol.test.js +278 -0
  891. package/test/mcp/roles.test.js +203 -0
  892. package/test/mcp/utils.test.js +245 -0
  893. package/test/notification/identity.test.js +155 -0
  894. package/test/routes/admin/create-post.test.js +362 -0
  895. package/test/routes/admin/database.test.js +133 -0
  896. package/test/routes/admin/deduplicate-image-alts.test.js +191 -0
  897. package/test/routes/admin/email-content-html.test.js +58 -0
  898. package/test/routes/admin/email-request-log.test.js +86 -0
  899. package/test/routes/admin/email.test.js +116 -0
  900. package/test/routes/admin/firestore-query.test.js +206 -0
  901. package/test/routes/admin/firestore.test.js +129 -0
  902. package/test/routes/admin/infer-contact.test.js +220 -0
  903. package/test/routes/admin/notification.test.js +199 -0
  904. package/test/routes/admin/post-convert-image.test.js +159 -0
  905. package/test/routes/admin/post-deploy-flag.test.js +81 -0
  906. package/test/routes/admin/post-download-error.test.js +90 -0
  907. package/test/routes/admin/post-resize-image.test.js +185 -0
  908. package/test/routes/admin/post.test.js +369 -0
  909. package/test/routes/admin/repo-content.test.js +223 -0
  910. package/test/routes/admin/stats.test.js +114 -0
  911. package/test/routes/admin/users-disable.test.js +63 -0
  912. package/test/routes/admin/users-list.test.js +71 -0
  913. package/test/routes/content/post.test.js +60 -0
  914. package/test/routes/general/uuid.test.js +133 -0
  915. package/test/routes/health.test.js +110 -0
  916. package/test/routes/marketing/campaign.test.js +184 -0
  917. package/test/routes/marketing/contact.test.js +416 -0
  918. package/test/routes/marketing/email-preferences.test.js +293 -0
  919. package/test/routes/marketing/push-send.test.js +34 -0
  920. package/test/routes/marketing/webhook-forward.test.js +63 -0
  921. package/test/routes/marketing/webhook.test.js +641 -0
  922. package/test/routes/payments/_route-harness.js +145 -0
  923. package/test/routes/payments/cancel-provider-errors.test.js +227 -0
  924. package/test/routes/payments/cancel-skip-guards.test.js +126 -0
  925. package/test/routes/payments/cancel-trialing.test.js +428 -0
  926. package/test/routes/payments/cancel.test.js +165 -0
  927. package/test/routes/payments/dedup-race.test.js +186 -0
  928. package/test/routes/payments/discount.test.js +82 -0
  929. package/test/routes/payments/dispute-alert.test.js +324 -0
  930. package/test/routes/payments/intent-discount-amounts.test.js +550 -0
  931. package/test/routes/payments/intent-discount-coupons.test.js +293 -0
  932. package/test/routes/payments/intent-one-time-metadata.test.js +122 -0
  933. package/test/routes/payments/intent-purchaser-guard.test.js +139 -0
  934. package/test/routes/payments/intent-zero-total.test.js +260 -0
  935. package/test/routes/payments/intent.test.js +413 -0
  936. package/test/routes/payments/plan.test.js +367 -0
  937. package/test/routes/payments/portal-return-url.test.js +107 -0
  938. package/test/routes/payments/portal.test.js +94 -0
  939. package/test/routes/payments/refund-one-time.test.js +254 -0
  940. package/test/routes/payments/refund-paypal-proration.test.js +190 -0
  941. package/test/routes/payments/refund.test.js +181 -0
  942. package/test/routes/payments/trial-eligibility.test.js +73 -0
  943. package/test/routes/payments/uncancel.test.js +270 -0
  944. package/test/routes/payments/webhook-stripe-invoice.test.js +129 -0
  945. package/test/routes/payments/webhook-stripe-refund-one-time.test.js +130 -0
  946. package/test/routes/payments/webhook-test-provider.test.js +156 -0
  947. package/test/routes/payments/webhook.test.js +115 -0
  948. package/test/routes/payments/winback-stripe-coupon.test.js +126 -0
  949. package/test/routes/payments/winback.test.js +597 -0
  950. package/test/routes/test/authenticate.test.js +79 -0
  951. package/test/routes/test/redirect.test.js +66 -0
  952. package/test/routes/test/reset-account.test.js +126 -0
  953. package/test/routes/test/roster.test.js +101 -0
  954. package/test/routes/test/schema.test.js +556 -0
  955. package/test/routes/test/usage.test.js +374 -0
  956. package/test/routes/user/api-keys.test.js +158 -0
  957. package/test/routes/user/connections-grant.test.js +759 -0
  958. package/test/routes/user/connections-identity.test.js +260 -0
  959. package/test/routes/user/connections-log-privacy.test.js +206 -0
  960. package/test/routes/user/connections-refresh-lease.test.js +696 -0
  961. package/test/routes/user/connections-return.test.js +261 -0
  962. package/test/routes/user/connections-uid.test.js +516 -0
  963. package/test/routes/user/delete.test.js +138 -0
  964. package/test/routes/user/feedback.test.js +106 -0
  965. package/test/routes/user/orders.test.js +233 -0
  966. package/test/routes/user/sessions.test.js +231 -0
  967. package/test/routes/user/settings-validate.test.js +84 -0
  968. package/test/routes/user/signup-emails.test.js +113 -0
  969. package/test/routes/user/signup-location.test.js +84 -0
  970. package/test/routes/user/signup-log-privacy.test.js +112 -0
  971. package/test/routes/user/signup.test.js +579 -0
  972. package/test/routes/user/subscription.test.js +101 -0
  973. package/test/routes/user/token.test.js +111 -0
  974. package/test/routes/user/user.test.js +158 -0
  975. package/test/routes/verts/cache.test.js +78 -0
  976. package/test/routes/verts/click-destination.test.js +76 -0
  977. package/test/routes/verts/crud.test.js +194 -0
  978. package/test/routes/verts/redirect.test.js +147 -0
  979. package/test/routes/verts/selection.test.js +237 -0
  980. package/test/routes/verts/serve.test.js +185 -0
  981. package/test/routes/verts/unit-document.test.js +117 -0
  982. package/test/rules/_environment.js +66 -0
  983. package/test/rules/brand-merge.test.js +195 -0
  984. package/test/rules/field-helpers.test.js +309 -0
  985. package/test/rules/notifications.test.js +577 -0
  986. package/test/rules/payments-carts.test.js +406 -0
  987. package/test/rules/sessions.test.js +170 -0
  988. package/test/rules/user.test.js +517 -0
  989. package/test/rules/verts.test.js +101 -0
  990. package/test/security/fetch-log-secrets.test.js +124 -0
  991. package/test/security/primitives.test.js +105 -0
  992. package/test/security/repo-pinning.test.js +77 -0
  993. 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
+ };