@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,982 @@
1
+ const os = require('os');
2
+ const path = require('path');
3
+ const Module = require('module');
4
+ const jetpack = require('fs-jetpack');
5
+ const chalk = require('chalk').default;
6
+
7
+ const HttpClient = require('./utils/http-client.js');
8
+ const assertions = require('./utils/assertions.js');
9
+ const { seed } = require('./seed.js');
10
+ const rulesClient = require('./utils/firestore-rules-client.js');
11
+ const { EXTENDED_MODE_WARNING } = require('./utils/extended-mode-warning.js');
12
+ const { SkipError } = require('../vendor/devkit/test/runner-core.js');
13
+ const { markRunnerActive } = require('../vendor/devkit/test/define-cases.js');
14
+ const { parseTestScope, isPathTargeted, noMatchMessage, FRAMEWORK_IDS } = require('../vendor/devkit/test/scope.js');
15
+ const { declaredLanes } = require('../utils/test-lanes.js');
16
+
17
+ // Test directories that belong to an OPT-IN lane, discovered only when that
18
+ // lane's own gate opened it (`npx omega test --lane=<name>`). The names come
19
+ // from this framework's own package.json `omega.testLanes` — the one home the
20
+ // gate modules and the brand-root fan-out read too (src/utils/test-lanes.js).
21
+ const LANE_DIRECTORIES = new Set(declaredLanes());
22
+
23
+ /**
24
+ * @omega.js/backend Integration Test Runner
25
+ * Supports standalone tests and test suites with sequential tests and shared state
26
+ */
27
+ class TestRunner {
28
+ constructor(options) {
29
+ options = options || {};
30
+
31
+ // Store config directly, only add defaults for truly optional fields
32
+ this.config = {
33
+ ...options,
34
+ bemDir: options.bemDir || path.resolve(__dirname, '..'),
35
+ timeout: options.timeout || 30000,
36
+ };
37
+
38
+ // Alias for backwards compatibility
39
+ this.options = this.config;
40
+
41
+ this.rulesContext = null;
42
+
43
+ this.accounts = null;
44
+ this.results = {
45
+ passed: 0,
46
+ failed: 0,
47
+ skipped: 0,
48
+ aborted: false, // pre-flight abort (config/health/accounts) — must exit non-zero
49
+ noMatch: null, // a named target that selected nothing (#814) — must exit non-zero
50
+ tests: [],
51
+ startTime: null,
52
+ endTime: null,
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Main run method
58
+ */
59
+ async run() {
60
+ // Abort if @omega.js/backend is running from the user's home directory (e.g., accidental ~/node_modules install)
61
+ const homeDir = os.homedir();
62
+ if (__dirname.startsWith(path.join(homeDir, 'node_modules'))) {
63
+ console.error(chalk.red('\n ERROR: @omega.js/backend is running from ~/node_modules (home directory install).'));
64
+ console.error(chalk.red(' This is likely an accidental global install that shadows local project copies.'));
65
+ console.error(chalk.red(` Fix: rm -rf ${path.join(homeDir, 'node_modules')} ${path.join(homeDir, 'package.json')} ${path.join(homeDir, 'package-lock.json')}`));
66
+ console.error(chalk.red(` Running from: ${__dirname}\n`));
67
+ process.exit(1);
68
+ }
69
+
70
+ // Set testing flag to skip external API calls (emails, SendGrid)
71
+ process.env.OMEGA_TEST_MODE = 'true';
72
+
73
+ // Claim the run before any case file is required: defineCases() only lets a
74
+ // spec through once a real runner is loading it (#630).
75
+ markRunnerActive();
76
+
77
+ this.results.startTime = Date.now();
78
+
79
+ console.log(chalk.bold('\n @omega.js/backend Integration Tests\n'));
80
+
81
+ // Warn if TEST_EXTENDED_MODE is enabled
82
+ if (process.env.TEST_EXTENDED_MODE) {
83
+ console.log(chalk.yellow.bold(` ${EXTENDED_MODE_WARNING[0]}`));
84
+ EXTENDED_MODE_WARNING.slice(1).forEach((line) => console.log(chalk.yellow(` ${line}`)));
85
+ console.log('');
86
+ }
87
+
88
+ // Which files this run selects
89
+ // @omega.js/backend tests are in the top-level test/ directory of the package
90
+ const frameworkTestsDir = path.resolve(__dirname, '../../test');
91
+ const projectTestsDir = path.join(this.options.projectDir, 'test');
92
+
93
+ // C5 scoping: bare/`project:`/`brand:` = project tests only,
94
+ // `framework:`/`omega:`/`mgr:`/`backend:` = the framework suite,
95
+ // `full:` = both. Framework self-test defaults to the framework source.
96
+ this.scope = parseTestScope(this.options.testPaths, {
97
+ frameworkAliases: FRAMEWORK_IDS['@omega.js/backend'],
98
+ selfTest: this.options.isFrameworkSelfTest,
99
+ });
100
+ for (const target of this.scope.invalid) {
101
+ console.log(chalk.yellow(` ⚠ Unknown test scope prefix ignored: ${target}`));
102
+ }
103
+
104
+ // A target that names a path and selects nothing is a typo, or a suite
105
+ // renamed out from under it: reporting "0 passing" at exit 0 there runs
106
+ // silently green ([#814](https://github.com/Omega-JS-Stack/omega/issues/814)).
107
+ // Ahead of the preflight below, so a typo costs a second, not a whole stack.
108
+ if (isPathTargeted(this.scope) && this.countSelected(frameworkTestsDir, projectTestsDir) === 0) {
109
+ const target = this.options.testPaths.join(' ');
110
+ console.log(chalk.red(` ${noMatchMessage(target)}`));
111
+ this.results.noMatch = target;
112
+ return this.results;
113
+ }
114
+
115
+ // Validate configuration
116
+ if (!this.validateConfig()) {
117
+ this.results.aborted = true;
118
+ return this.results;
119
+ }
120
+
121
+ // Health check (use basic http client without accounts)
122
+ // Use hosting URL for all requests (rewrites to omega_api function)
123
+ const healthHttp = new HttpClient({
124
+ apiUrl: this.options.apiUrl,
125
+ timeout: this.options.timeout,
126
+ });
127
+
128
+ const healthy = await this.healthCheck(healthHttp);
129
+ if (!healthy) {
130
+ this.results.aborted = true;
131
+ return this.results;
132
+ }
133
+
134
+ // Setup accounts
135
+ const accountsReady = await this.setupAccounts();
136
+ if (!accountsReady) {
137
+ this.results.aborted = true;
138
+ return this.results;
139
+ }
140
+
141
+ // Run @omega.js/backend default tests
142
+ if (this.scope.sources.includes('framework') && jetpack.exists(frameworkTestsDir)) {
143
+ console.log(chalk.bold(' @omega.js/backend Core Tests'));
144
+ await this.runTestsInDir(frameworkTestsDir, 'backend');
145
+ }
146
+
147
+ // Run project-specific tests
148
+ if (this.scope.sources.includes('project') && jetpack.exists(projectTestsDir)) {
149
+ console.log(chalk.bold('\n Project Tests'));
150
+ await this.runTestsInDir(projectTestsDir, 'project');
151
+ }
152
+
153
+ // Cleanup rules context
154
+ if (this.rulesContext) {
155
+ await this.rulesContext.cleanup();
156
+ }
157
+
158
+ // Report results
159
+ this.reportResults();
160
+
161
+ this.results.endTime = Date.now();
162
+ return this.results;
163
+ }
164
+
165
+ /**
166
+ * Validate configuration
167
+ */
168
+ validateConfig() {
169
+ if (!this.options.apiUrl) {
170
+ console.log(chalk.red(' ✗ Missing apiUrl'));
171
+ console.log(chalk.gray(' Set OMEGA_API_URL environment variable or pass --url flag'));
172
+ return false;
173
+ }
174
+
175
+ if (!this.options.adminKey) {
176
+ console.log(chalk.red(' ✗ Missing adminKey'));
177
+ console.log(chalk.gray(' Set OMEGA_ADMIN_KEY environment variable or pass --key flag'));
178
+ return false;
179
+ }
180
+
181
+ if (!this.options.webhookKey) {
182
+ console.log(chalk.red(' ✗ Missing webhookKey'));
183
+ console.log(chalk.gray(' Set OMEGA_WEBHOOK_KEY environment variable or pass --webhook-key flag'));
184
+ return false;
185
+ }
186
+
187
+ if (!this.options.brand?.id) {
188
+ console.log(chalk.red(' ✗ Missing brand.id'));
189
+ console.log(chalk.gray(' Could not determine brand ID from configuration'));
190
+ return false;
191
+ }
192
+
193
+ if (!this.options.domain) {
194
+ console.log(chalk.red(' ✗ Missing domain'));
195
+ console.log(chalk.gray(' Could not determine the brand host from brand.url'));
196
+ return false;
197
+ }
198
+
199
+ return true;
200
+ }
201
+
202
+ /**
203
+ * Check if server is healthy
204
+ */
205
+ async healthCheck(http) {
206
+ process.stdout.write(chalk.gray(' Checking server health... '));
207
+
208
+ try {
209
+ const response = await http.get('omega/health');
210
+
211
+ if (response.success) {
212
+ console.log(chalk.green('✓'));
213
+
214
+ // Abort if the running emulator belongs to a different project.
215
+ // This catches the case where you run `npx omega test` in project A
216
+ // while project B's emulator is still up on the same ports — requests
217
+ // hit the wrong hosting rewrites and tests fail with mysterious 404s.
218
+ const mismatch = await this.checkProjectMismatch(response.data);
219
+ if (mismatch) {
220
+ return false;
221
+ }
222
+
223
+ // Report the live mode the emulator just confirmed. The test command
224
+ // writes `.temp/test-mode.json` before invoking us; the emulator's
225
+ // file-watcher mutates its `process.env.TEST_EXTENDED_MODE` to match;
226
+ // the health endpoint re-reads the file as a freshness guard. By
227
+ // construction these are equal — no mismatch warning needed.
228
+ const emulatorExtended = !!response.data?.testExtendedMode;
229
+ console.log(chalk.gray(` Mode: ${emulatorExtended ? 'extended (real external APIs)' : 'normal (external APIs skipped)'}`));
230
+
231
+ return true;
232
+ }
233
+
234
+ console.log(chalk.red('✗'));
235
+ console.log(chalk.red(` Server not responding: ${response.error}`));
236
+ console.log(chalk.gray(` Make sure your functions are deployed and running at ${this.options.apiUrl}`));
237
+ return false;
238
+ } catch (error) {
239
+ console.log(chalk.red('✗'));
240
+ console.log(chalk.red(` Health check failed: ${error.message}`));
241
+ return false;
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Verify the running emulator belongs to this project. The hub's
247
+ * GET /emulators carries no projectId (confirmed against firebase-tools 15.x),
248
+ * so that leg always comes back empty; the health endpoint's projectId field
249
+ * (added in @omega.js/backend 5.3.3+) is the working source. Returns true
250
+ * (= mismatch, abort) if the project IDs differ.
251
+ */
252
+ async checkProjectMismatch(healthData) {
253
+ const expectedProjectId = this.options.cloud?.config?.projectId;
254
+ if (!expectedProjectId) {
255
+ return false;
256
+ }
257
+
258
+ let emulatorProjectId;
259
+
260
+ // Try the Firebase Emulator Hub first (version-independent, always correct)
261
+ try {
262
+ const http = require('http');
263
+ const body = await new Promise((resolve, reject) => {
264
+ const req = http.get('http://localhost:4400/emulators', (res) => {
265
+ let data = '';
266
+ res.on('data', (chunk) => { data += chunk; });
267
+ res.on('end', () => resolve(data));
268
+ });
269
+ req.on('error', reject);
270
+ req.setTimeout(3000, () => { req.destroy(); reject(new Error('timeout')); });
271
+ });
272
+ emulatorProjectId = JSON.parse(body).projectId;
273
+ } catch (e) {
274
+ // Hub unreachable — fall back to health endpoint
275
+ }
276
+
277
+ // Fall back to the health endpoint's projectId (@omega.js/backend 5.3.3+)
278
+ if (!emulatorProjectId) {
279
+ emulatorProjectId = healthData?.projectId;
280
+ }
281
+
282
+ if (emulatorProjectId && emulatorProjectId !== expectedProjectId) {
283
+ console.log(chalk.red(`\n ✗ Project mismatch: the running emulator belongs to "${emulatorProjectId}" but this project is "${expectedProjectId}".`));
284
+ console.log(chalk.red(` Stop the other emulator first, then run: npx omega emulator`));
285
+ return true;
286
+ }
287
+
288
+ return false;
289
+ }
290
+
291
+ /**
292
+ * Setup test accounts - delegates to the shared seed module, then initializes
293
+ * the rules-testing context (test-runner-specific, not needed for standalone seeding).
294
+ */
295
+ async setupAccounts() {
296
+ const result = await seed({
297
+ admin: this.options.admin,
298
+ domain: this.options.domain,
299
+ config: this.config,
300
+ projectDir: this.options.projectDir,
301
+ Manager: this.config.Manager,
302
+ ctx: this.config.ctx,
303
+ });
304
+
305
+ if (!result.accounts) {
306
+ return false;
307
+ }
308
+
309
+ this.accounts = result.accounts;
310
+
311
+ // Initialize rules testing context for security rules tests
312
+ process.stdout.write(chalk.gray(' Initializing rules testing context... '));
313
+ try {
314
+ this.rulesContext = await rulesClient.createRulesContext({
315
+ projectId: this.options.cloud?.config?.projectId,
316
+ rulesPath: this.options.rulesPath,
317
+ port: this.options.emulatorPorts?.firestore,
318
+ accounts: this.accounts,
319
+ });
320
+ console.log(chalk.green('✓'));
321
+ } catch (error) {
322
+ console.log(chalk.red(`✗ (${error.message})`));
323
+ return false;
324
+ }
325
+
326
+ return true;
327
+ }
328
+
329
+ /**
330
+ * Run all tests in a directory
331
+ */
332
+ async runTestsInDir(dir, source) {
333
+ const testFiles = this.discoverTests(dir);
334
+ const filteredTests = this.filterTests(testFiles, source);
335
+
336
+ for (const testFile of filteredTests) {
337
+ await this.runTestFile(testFile, source);
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Discover test files in directory
343
+ */
344
+ discoverTests(dir) {
345
+ const tests = [];
346
+ const items = jetpack.list(dir) || [];
347
+
348
+ for (const item of items) {
349
+ // Skip _-prefixed files and directories (fixtures, helpers, internal data).
350
+ // Matches EM/BXM/UJM convention — `test/_fixtures/`, `test/_helpers/`, etc.
351
+ if (item.startsWith('_')) {
352
+ continue;
353
+ }
354
+
355
+ // Skip the boot/ smoke layer except during framework self-test. It targets
356
+ // the bundled fixture project and would be redundant noise in a real
357
+ // consumer's run (mirrors EM/BXM/UJM excluding boot/** for consumers).
358
+ if (item === 'boot' && !this.options.isFrameworkSelfTest) {
359
+ continue;
360
+ }
361
+
362
+ // An opt-in lane's suites are named for the lane and are UNREACHABLE by
363
+ // any run that did not ask for it: they need credentials and the network,
364
+ // and the `--lane=` gate is the only thing that sets this
365
+ // ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)). A path
366
+ // filter naming the directory does not open it — only the gate does.
367
+ if (LANE_DIRECTORIES.has(item) && process.env.OMEGA_TEST_LANE !== item) {
368
+ continue;
369
+ }
370
+
371
+ const fullPath = path.join(dir, item);
372
+ const stat = jetpack.inspect(fullPath);
373
+
374
+ if (stat.type === 'dir') {
375
+ tests.push(...this.discoverTests(fullPath));
376
+ } else if (stat.type === 'file' && item.endsWith('.test.js')) {
377
+ tests.push(fullPath);
378
+ }
379
+ }
380
+
381
+ return tests;
382
+ }
383
+
384
+ /**
385
+ * How many test files this run's scope selects, across both sources: the
386
+ * count a named target has to beat to be a real selection rather than a typo
387
+ * ([#814](https://github.com/Omega-JS-Stack/omega/issues/814)).
388
+ *
389
+ * @param {string} frameworkTestsDir - @omega.js/backend's own test/ dir
390
+ * @param {string} projectTestsDir - the consumer project's test/ dir
391
+ * @returns {number} Files the run would load
392
+ */
393
+ countSelected(frameworkTestsDir, projectTestsDir) {
394
+ let count = 0;
395
+
396
+ if (this.scope.sources.includes('framework') && jetpack.exists(frameworkTestsDir)) {
397
+ count += this.filterTests(this.discoverTests(frameworkTestsDir), 'backend').length;
398
+ }
399
+
400
+ if (this.scope.sources.includes('project') && jetpack.exists(projectTestsDir)) {
401
+ count += this.filterTests(this.discoverTests(projectTestsDir), 'project').length;
402
+ }
403
+
404
+ return count;
405
+ }
406
+
407
+ /**
408
+ * Filter tests for a source using the C5 scope's prefix-stripped paths
409
+ * (source selection already happened in run() via parseTestScope — this
410
+ * only path-matches within the source's own tree).
411
+ */
412
+ filterTests(testFiles, source) {
413
+ const filters = this.scope.filters[source === 'backend' ? 'framework' : 'project'];
414
+ if (filters.length === 0) {
415
+ return testFiles;
416
+ }
417
+
418
+ return testFiles.filter((testFile) => {
419
+ const relativePath = this.getRelativeTestPath(testFile, source);
420
+ return filters.some((filterPath) => relativePath.startsWith(filterPath)
421
+ || relativePath === `${filterPath.replace(/(\.test)?\.js$/, '')}.test.js`);
422
+ });
423
+ }
424
+
425
+ /**
426
+ * Get relative test path for display
427
+ */
428
+ getRelativeTestPath(testFile, source) {
429
+ if (source === 'backend') {
430
+ return path.relative(path.resolve(__dirname, '../../test'), testFile);
431
+ }
432
+ return path.relative(path.join(this.options.projectDir, 'test'), testFile);
433
+ }
434
+
435
+ /**
436
+ * Run a test file (handles both standalone tests and suites)
437
+ */
438
+ async runTestFile(testFile, source) {
439
+ const relativePath = this.getRelativeTestPath(testFile, source);
440
+ let testModule;
441
+
442
+ try {
443
+ const searchPaths = [
444
+ // The target root + its install — deps live on the ONE target manifest
445
+ // (src/dist pillar); dist/node_modules covers legacy installs
446
+ this.options.projectDir,
447
+ path.join(this.options.projectDir, 'node_modules'),
448
+ path.join(this.options.projectDir, 'dist', 'node_modules'),
449
+ path.resolve(__dirname, '../../'),
450
+ ];
451
+ const origResolve = Module._resolveFilename.bind(Module);
452
+ Module._resolveFilename = function (request, parent, isMain, options) {
453
+ // Try normal resolution first (preserves nested node_modules traversal)
454
+ try {
455
+ return origResolve(request, parent, isMain, options);
456
+ } catch (err) {
457
+ // Fallback: try resolving from project's search paths
458
+ if (!request.startsWith('.') && !path.isAbsolute(request)) {
459
+ const extra = (options && options.paths) ? options.paths : [];
460
+ return origResolve(request, parent, isMain, {
461
+ ...options,
462
+ paths: [...extra, ...searchPaths],
463
+ });
464
+ }
465
+ throw err;
466
+ }
467
+ };
468
+ try {
469
+ testModule = require(testFile);
470
+ } finally {
471
+ Module._resolveFilename = origResolve;
472
+ }
473
+ } catch (error) {
474
+ console.log(chalk.red(` ✗ ${relativePath}`));
475
+ console.log(chalk.red(` Failed to load: ${error.message}`));
476
+ this.results.failed++;
477
+ this.results.tests.push({
478
+ path: relativePath,
479
+ passed: false,
480
+ error: `Failed to load: ${error.message}`,
481
+ });
482
+ return;
483
+ }
484
+
485
+ // Check if entire file should be skipped
486
+ if (testModule.skip) {
487
+ const skipReason = typeof testModule.skip === 'string' ? testModule.skip : '';
488
+ const description = testModule.description || relativePath;
489
+ console.log(chalk.yellow(` ○ ${description}`) + chalk.gray(` (skipped${skipReason ? `: ${skipReason}` : ''})`));
490
+
491
+ this.results.skipped++;
492
+ this.results.tests.push({
493
+ path: relativePath,
494
+ description,
495
+ skipped: true,
496
+ skipReason,
497
+ });
498
+ return;
499
+ }
500
+
501
+ // Check if this is a suite/group (has tests array) or standalone test
502
+ if (testModule.type === 'suite' || testModule.type === 'group' || Array.isArray(testModule.tests)) {
503
+ await this.runSuite(testModule, relativePath);
504
+ } else if (Array.isArray(testModule)) {
505
+ // Plain array treated as a group (independent tests)
506
+ await this.runSuite({ type: 'group', tests: testModule }, relativePath);
507
+ } else {
508
+ await this.runStandaloneTest(testModule, relativePath);
509
+ }
510
+ }
511
+
512
+ /**
513
+ * Run a test suite with sequential tests and shared state
514
+ */
515
+ async runSuite(suite, relativePath) {
516
+ const suiteDescription = suite.description || relativePath;
517
+ const suiteTimeout = suite.timeout || this.options.timeout;
518
+ const tests = suite.tests || [];
519
+
520
+ console.log(chalk.cyan(` ⤷ ${suiteDescription}`));
521
+
522
+ // Shared state across all tests in the suite
523
+ const state = {};
524
+
525
+ for (let i = 0; i < tests.length; i++) {
526
+ const test = tests[i];
527
+ const testName = test.name || `step-${i + 1}`;
528
+ const testTimeout = test.timeout || suiteTimeout;
529
+ const auth = test.auth || suite.auth || 'none';
530
+
531
+ // Check if test should be skipped
532
+ if (test.skip) {
533
+ const skipReason = typeof test.skip === 'string' ? test.skip : '';
534
+ console.log(chalk.yellow(` ○ ${testName}`) + chalk.gray(` (skipped${skipReason ? `: ${skipReason}` : ''})`));
535
+
536
+ this.results.skipped++;
537
+ this.results.tests.push({
538
+ path: `${relativePath}:${testName}`,
539
+ description: testName,
540
+ skipped: true,
541
+ skipReason,
542
+ suite: suiteDescription,
543
+ });
544
+ continue;
545
+ }
546
+
547
+ // Create context with shared state
548
+ const context = this.createContext(auth, state);
549
+
550
+ const startTime = Date.now();
551
+
552
+ try {
553
+ await Promise.race([
554
+ test.run(context),
555
+ new Promise((_, reject) =>
556
+ setTimeout(() => reject(new Error('Test timeout')), testTimeout)
557
+ ),
558
+ ]);
559
+
560
+ const duration = Date.now() - startTime;
561
+ console.log(chalk.green(` ✓ ${testName}`) + chalk.gray(` (${duration}ms)`));
562
+
563
+ this.results.passed++;
564
+ this.results.tests.push({
565
+ path: `${relativePath}:${testName}`,
566
+ description: testName,
567
+ passed: true,
568
+ duration,
569
+ suite: suiteDescription,
570
+ });
571
+
572
+ // Run cleanup if defined
573
+ if (test.cleanup) {
574
+ try {
575
+ await test.cleanup(context);
576
+ } catch (cleanupError) {
577
+ console.log(chalk.yellow(` ⚠ Cleanup failed: ${cleanupError.message}`));
578
+ }
579
+ }
580
+ } catch (error) {
581
+ const duration = Date.now() - startTime;
582
+
583
+ // Check for runtime skip (test called skip())
584
+ if (error.name === 'SkipError') {
585
+ const skipReason = error.message;
586
+ console.log(chalk.yellow(` ○ ${testName}`) + chalk.gray(` (skipped: ${skipReason})`));
587
+
588
+ this.results.skipped++;
589
+ this.results.tests.push({
590
+ path: `${relativePath}:${testName}`,
591
+ description: testName,
592
+ skipped: true,
593
+ skipReason,
594
+ duration,
595
+ suite: suiteDescription,
596
+ });
597
+
598
+ // For suites (sequential, state-dependent tests), a skip on any step means
599
+ // subsequent steps can't run cleanly — propagate skip to the rest of the suite.
600
+ // Groups (independent tests) continue normally.
601
+ const shouldStopOnSkip = suite.type !== 'group' && suite.stopOnFailure !== false;
602
+ if (shouldStopOnSkip) {
603
+ const remaining = tests.length - i - 1;
604
+ if (remaining > 0) {
605
+ console.log(chalk.yellow(` Skipping ${remaining} remaining test(s) in suite (suite-level skip)`));
606
+ this.results.skipped += remaining;
607
+ }
608
+ break;
609
+ }
610
+
611
+ continue;
612
+ }
613
+
614
+ console.log(chalk.red(` ✗ ${testName}`) + chalk.gray(` (${duration}ms)`));
615
+ console.log(chalk.red(` ${error.message}`));
616
+
617
+ this.results.failed++;
618
+ this.results.tests.push({
619
+ path: `${relativePath}:${testName}`,
620
+ description: testName,
621
+ passed: false,
622
+ duration,
623
+ error: error.message,
624
+ suite: suiteDescription,
625
+ });
626
+
627
+ // Stop the suite on first failure (sequential tests depend on each other)
628
+ // Groups (type: 'group') continue running all tests regardless of failures
629
+ const shouldStopOnFailure = suite.type !== 'group' && suite.stopOnFailure !== false;
630
+ if (shouldStopOnFailure) {
631
+ const remaining = tests.length - i - 1;
632
+ if (remaining > 0) {
633
+ console.log(chalk.yellow(` Skipping ${remaining} remaining test(s) in suite`));
634
+ this.results.skipped += remaining;
635
+ }
636
+ break;
637
+ }
638
+ }
639
+ }
640
+
641
+ // Run suite-level cleanup
642
+ if (suite.cleanup) {
643
+ try {
644
+ const context = this.createContext('admin', state);
645
+ await suite.cleanup(context);
646
+ } catch (cleanupError) {
647
+ console.log(chalk.yellow(` ⚠ Suite cleanup failed: ${cleanupError.message}`));
648
+ }
649
+ }
650
+ }
651
+
652
+ /**
653
+ * Run a standalone test
654
+ */
655
+ async runStandaloneTest(testModule, relativePath) {
656
+ const description = testModule.description || relativePath;
657
+ const timeout = testModule.timeout || this.options.timeout;
658
+ const auth = testModule.auth || testModule.authLevel || 'none';
659
+
660
+ // Create context (no shared state for standalone tests)
661
+ const context = this.createContext(auth);
662
+
663
+ const startTime = Date.now();
664
+
665
+ try {
666
+ await Promise.race([
667
+ testModule.run(context),
668
+ new Promise((_, reject) =>
669
+ setTimeout(() => reject(new Error('Test timeout')), timeout)
670
+ ),
671
+ ]);
672
+
673
+ const duration = Date.now() - startTime;
674
+ console.log(chalk.green(` ✓ ${description}`) + chalk.gray(` (${duration}ms)`));
675
+
676
+ this.results.passed++;
677
+ this.results.tests.push({
678
+ path: relativePath,
679
+ description,
680
+ passed: true,
681
+ duration,
682
+ });
683
+
684
+ // Run cleanup if defined
685
+ if (testModule.cleanup) {
686
+ try {
687
+ await testModule.cleanup(context);
688
+ } catch (cleanupError) {
689
+ console.log(chalk.yellow(` ⚠ Cleanup failed: ${cleanupError.message}`));
690
+ }
691
+ }
692
+ } catch (error) {
693
+ const duration = Date.now() - startTime;
694
+
695
+ // Check for runtime skip (test called skip())
696
+ if (error.name === 'SkipError') {
697
+ const skipReason = error.message;
698
+ console.log(chalk.yellow(` ○ ${description}`) + chalk.gray(` (skipped: ${skipReason})`));
699
+
700
+ this.results.skipped++;
701
+ this.results.tests.push({
702
+ path: relativePath,
703
+ description,
704
+ skipped: true,
705
+ skipReason,
706
+ duration,
707
+ });
708
+ return;
709
+ }
710
+
711
+ console.log(chalk.red(` ✗ ${description}`) + chalk.gray(` (${duration}ms)`));
712
+ console.log(chalk.red(` ${error.message}`));
713
+
714
+ this.results.failed++;
715
+ this.results.tests.push({
716
+ path: relativePath,
717
+ description,
718
+ passed: false,
719
+ duration,
720
+ error: error.message,
721
+ });
722
+ }
723
+ }
724
+
725
+ /**
726
+ * Create test context with all utilities
727
+ * @param {string} auth - Default auth level: 'admin', 'basic', 'premium-active', 'premium-expired', 'none'
728
+ * @param {object} state - Shared state object (for suites)
729
+ */
730
+ createContext(auth, state) {
731
+ // Create HTTP client with accounts for as() method
732
+ // Use hosting URL for all requests (rewrites to omega_api function)
733
+ const http = new HttpClient({
734
+ apiUrl: this.options.apiUrl,
735
+ timeout: this.options.timeout,
736
+ accounts: this.accounts,
737
+ adminKey: this.options.adminKey,
738
+ webhookKey: this.options.webhookKey,
739
+ });
740
+
741
+ // Set default auth
742
+ if (auth === 'admin') {
743
+ http.setAuth('adminKey', { key: this.options.adminKey });
744
+ } else if (auth === 'none') {
745
+ http.setAuth('none');
746
+ } else if (auth === 'user') {
747
+ // Alias for basic
748
+ if (this.accounts?.basic?.privateKey) {
749
+ http.setAuth('privateKey', { privateKey: this.accounts.basic.privateKey });
750
+ }
751
+ } else if (this.accounts?.[auth]?.privateKey) {
752
+ // Dynamic lookup — any account type with a privateKey
753
+ http.setAuth('privateKey', { privateKey: this.accounts[auth].privateKey });
754
+ } else {
755
+ http.setAuth('none');
756
+ }
757
+
758
+ // Create firestore helper (only if admin SDK available)
759
+ const firestore = this.options.admin
760
+ ? this.createFirestoreHelper()
761
+ : null;
762
+
763
+ // Create waitFor helper
764
+ const waitFor = this.createWaitFor();
765
+
766
+ // Create pubsub helper
767
+ const pubsub = this.createPubSubHelper();
768
+
769
+ // Skip function for runtime skipping
770
+ const skip = (reason) => {
771
+ throw new SkipError(reason);
772
+ };
773
+
774
+ // Precomputed product metadata for payment tests — SSOT for all product-aware tests.
775
+ // Each product gets: stripeProductId, frequency, interval, price resolved from config.
776
+ // Tests use payments.products[id].* instead of recomputing per-test.
777
+ const FREQ_TO_INTERVAL = { daily: 'day', weekly: 'week', monthly: 'month', annually: 'year' };
778
+ const products = this.config.payment?.products || [];
779
+ const stripeProductIds = Object.fromEntries(
780
+ products.map((p) => [p.id, p.stripe?.productId || `_test_${p.id}`])
781
+ );
782
+ const productMeta = Object.fromEntries(
783
+ products.map((p) => {
784
+ const freq = p.prices ? Object.keys(p.prices)[0] : null;
785
+ return [p.id, {
786
+ id: p.id,
787
+ name: p.name,
788
+ type: p.type,
789
+ stripeProductId: p.stripe?.productId || `_test_${p.id}`,
790
+ frequency: freq,
791
+ interval: FREQ_TO_INTERVAL[freq] || null,
792
+ price: freq ? p.prices[freq] : 0,
793
+ trial: p.trial || null,
794
+ }];
795
+ })
796
+ );
797
+
798
+ return {
799
+ http,
800
+ accounts: this.accounts,
801
+ assert: assertions,
802
+ state: state || {},
803
+ firestore,
804
+ waitFor,
805
+ pubsub,
806
+ skip,
807
+ admin: this.config.admin,
808
+ // Real @omega.js/backend Manager + ctx, booted by run-tests.js with OMEGA_TEST_RUNNER=1.
809
+ // Tests can call Manager.AI(), Manager.Email(), Manager.User(), etc. exactly
810
+ // like production code — no stubs.
811
+ Manager: this.config.Manager,
812
+ ctx: this.config.ctx,
813
+ rules: this.rulesContext,
814
+ config: this.config,
815
+ payments: { stripeProductIds, products: productMeta },
816
+ };
817
+ }
818
+
819
+ /**
820
+ * Create Firestore helper for direct database access
821
+ */
822
+ createFirestoreHelper() {
823
+ const admin = this.options.admin;
824
+ const db = admin.firestore();
825
+
826
+ return {
827
+ /**
828
+ * Get a document
829
+ * @param {string} docPath - Document path (e.g., 'users/abc123')
830
+ * @returns {Promise<object|null>} Document data or null
831
+ */
832
+ async get(docPath) {
833
+ const doc = await db.doc(docPath).get();
834
+ return doc.exists ? doc.data() : null;
835
+ },
836
+
837
+ /**
838
+ * Check if a document exists
839
+ * @param {string} docPath - Document path
840
+ * @returns {Promise<boolean>}
841
+ */
842
+ async exists(docPath) {
843
+ const doc = await db.doc(docPath).get();
844
+ return doc.exists;
845
+ },
846
+
847
+ /**
848
+ * Set a document
849
+ * @param {string} docPath - Document path
850
+ * @param {object} data - Data to set
851
+ * @param {object} options - Firestore set options
852
+ */
853
+ async set(docPath, data, options) {
854
+ await db.doc(docPath).set(data, options || {});
855
+ },
856
+
857
+ /**
858
+ * Delete a document
859
+ * @param {string} docPath - Document path
860
+ */
861
+ async delete(docPath) {
862
+ await db.doc(docPath).delete();
863
+ },
864
+
865
+ /**
866
+ * Query a collection
867
+ * @param {string} collectionPath - Collection path
868
+ * @returns {object} Firestore collection reference
869
+ */
870
+ collection(collectionPath) {
871
+ return db.collection(collectionPath);
872
+ },
873
+ };
874
+ }
875
+
876
+ /**
877
+ * Create waitFor helper for polling conditions
878
+ */
879
+ createWaitFor() {
880
+ /**
881
+ * Wait for a condition to be true
882
+ * @param {Function} condition - Async function that returns truthy when ready
883
+ * @param {number} timeoutMs - Maximum time to wait (default 5000)
884
+ * @param {number} intervalMs - Polling interval (default 100)
885
+ * @returns {Promise<*>} The truthy value returned by condition
886
+ */
887
+ return async function waitFor(condition, timeoutMs, intervalMs) {
888
+ timeoutMs = timeoutMs || 5000;
889
+ intervalMs = intervalMs || 100;
890
+
891
+ const startTime = Date.now();
892
+
893
+ while (Date.now() - startTime < timeoutMs) {
894
+ try {
895
+ const result = await condition();
896
+ if (result) {
897
+ return result;
898
+ }
899
+ } catch (error) {
900
+ // Condition threw - keep polling
901
+ }
902
+ await new Promise(resolve => setTimeout(resolve, intervalMs));
903
+ }
904
+
905
+ throw new Error(`waitFor timed out after ${timeoutMs}ms`);
906
+ };
907
+ }
908
+
909
+ /**
910
+ * Create PubSub helper for triggering scheduled functions
911
+ */
912
+ createPubSubHelper() {
913
+ const config = this.config;
914
+
915
+ // The port the RUNNING emulator resolved, never the classic 8085. Anything
916
+ // else on the machine holding 8085 bumps this stack's Pub/Sub emulator off
917
+ // it (N7), and a hardcoded endpoint then published into whatever owns that
918
+ // port instead: the scheduled function never fired HERE, so every
919
+ // cron-driven test sat out its full waitFor deadline with no error to name
920
+ // ([#404](https://github.com/Omega-JS-Stack/omega/issues/404)).
921
+ const pubsubPort = this.options.emulatorPorts?.pubsub;
922
+
923
+ return {
924
+ /**
925
+ * Trigger a Firebase scheduled function via PubSub
926
+ * @param {string} functionName - The function name (e.g., 'omega_cronDaily')
927
+ * @returns {Promise<string>} The message ID
928
+ */
929
+ async trigger(functionName) {
930
+ if (!pubsubPort) {
931
+ throw new Error(`Cannot trigger ${functionName}: the test config carries no resolved Pub/Sub port (emulatorPorts.pubsub)`);
932
+ }
933
+
934
+ const { PubSub } = require('@google-cloud/pubsub');
935
+ const pubsub = new PubSub({
936
+ projectId: config.cloud?.config?.projectId,
937
+ apiEndpoint: `127.0.0.1:${pubsubPort}`,
938
+ });
939
+
940
+ const topicName = `firebase-schedule-${functionName}`;
941
+
942
+ // Get or create the topic (emulator may not have it yet)
943
+ let topic = pubsub.topic(topicName);
944
+ const [exists] = await topic.exists();
945
+
946
+ if (!exists) {
947
+ [topic] = await pubsub.createTopic(topicName);
948
+ }
949
+
950
+ const messageId = await topic.publishMessage({ json: {} });
951
+ return messageId;
952
+ },
953
+ };
954
+ }
955
+
956
+ /**
957
+ * Report final results
958
+ */
959
+ reportResults() {
960
+ const total = this.results.passed + this.results.failed + this.results.skipped;
961
+ const duration = Date.now() - this.results.startTime;
962
+
963
+ console.log(`\n ${chalk.bold('Results')}`);
964
+ console.log(` ${chalk.green(`${this.results.passed} passing`)}`);
965
+
966
+ if (this.results.failed > 0) {
967
+ console.log(` ${chalk.red(`${this.results.failed} failing`)}`);
968
+ }
969
+
970
+ if (this.results.skipped > 0) {
971
+ console.log(` ${chalk.yellow(`${this.results.skipped} skipped`)}`);
972
+ }
973
+
974
+ console.log(chalk.gray(`\n Total: ${total} tests in ${duration}ms\n`));
975
+ }
976
+ }
977
+
978
+ // The lane list rides alongside the runner: a lane whose directory name drifted
979
+ // from its `--lane=` name would be silently unreachable, or worse, silently open.
980
+ TestRunner.LANE_DIRECTORIES = LANE_DIRECTORIES;
981
+
982
+ module.exports = TestRunner;