@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,622 @@
1
+ /**
2
+ * Test: the compiled Firestore rules model
3
+ * ([#255](https://github.com/Omega-JS-Stack/omega/issues/255),
4
+ * [#288](https://github.com/Omega-JS-Stack/omega/issues/288),
5
+ * [#353](https://github.com/Omega-JS-Stack/omega/issues/353)).
6
+ *
7
+ * The brand's `firestore.rules` is SOURCE (pure rules, no hooks); the framework
8
+ * half ships inside this package; every stage compiles the two into
9
+ * `dist/firestore.rules`, which firebase.json points the emulator AND
10
+ * `firebase deploy` at. A brand match block whose path names a framework block
11
+ * MERGES into it, which is how a brand tightens.
12
+ *
13
+ * Everything here is string work against temp dirs — no project, no emulator.
14
+ * What the merged rules DO (a brand condition actually denying a client write,
15
+ * the field helpers on create and update) is proven against the real emulator
16
+ * in test/rules/brand-merge.test.js and test/rules/field-helpers.test.js.
17
+ *
18
+ * Run: npx omega test backend:cli/rules-compile
19
+ */
20
+ const path = require('path');
21
+ const jetpack = require('fs-jetpack');
22
+ const {
23
+ BRAND_RULES_SEED,
24
+ COMPILED_RULES_FILE,
25
+ RETIRED_NAMES,
26
+ RULES_MIGRATION_COMMAND,
27
+ RULES_VERSION,
28
+ compileRules,
29
+ compileFirestoreRules,
30
+ ensureBrandRulesSource,
31
+ extractDocumentsBody,
32
+ needsRulesMigration,
33
+ } = require('../../dist/cli/utils/compile-rules.js');
34
+ const { stageFunctions } = require('../../dist/cli/utils/stage-functions.js');
35
+ const defineCases = require('../../dist/vendor/devkit/test/define-cases.js');
36
+
37
+ const PACKAGE_DIR = path.join(__dirname, '..', '..');
38
+ const TEMPLATES_DIR = path.join(PACKAGE_DIR, 'templates');
39
+ const FIXTURE_DIR = path.join(PACKAGE_DIR, 'dist', 'test', 'fixtures', 'firebase-project');
40
+
41
+ // A pre-#255 consumer file: the brand's own rules above the managed block.
42
+ const LEGACY_SOURCE = [
43
+ 'rules_version = \'2\';',
44
+ 'service cloud.firestore {',
45
+ ' match /databases/{database}/documents {',
46
+ ' // Custom rules',
47
+ ' match /leaderboards/{id} {',
48
+ ' allow read: if true;',
49
+ ' allow write: if isAdmin();',
50
+ ' }',
51
+ '',
52
+ ' // ========== OMEGA Rules (v1.0.0) ==========',
53
+ ' match /users/{uid} {',
54
+ ' allow read: if belongsTo(uid);',
55
+ ' allow write: if belongsTo(uid) && !isWritingProtectedUserField();',
56
+ ' }',
57
+ ' // ========== End OMEGA Rules ==========',
58
+ ' }',
59
+ '}',
60
+ '',
61
+ ].join('\n');
62
+
63
+ // A v2 (0.36.0) consumer file: the hook era. `protectedFields()` still carries
64
+ // the shipped default; `canWriteUser()` carries the brand's own code, and calls
65
+ // a helper v3 renamed.
66
+ const HOOK_ERA_SOURCE = [
67
+ '// ============================================================================',
68
+ '// YOUR Firestore rules. This file is the SOURCE and it is yours — @omega.js/backend',
69
+ '// never rewrites it (it only appends a framework hook back if one goes missing).',
70
+ '//',
71
+ '// isAuthenticated() authUid() authEmail()',
72
+ '// belongsTo(id) isAdmin() emailVerified()',
73
+ '// ============================================================================',
74
+ 'rules_version = \'2\';',
75
+ 'service cloud.firestore {',
76
+ ' match /databases/{database}/documents {',
77
+ ' // ─── Your rules ──────────────────────────────────────────────────────────',
78
+ ' match /leaderboards/{id} {',
79
+ ' allow read: if true;',
80
+ ' allow write: if isAdmin();',
81
+ ' }',
82
+ '',
83
+ ' // ─── Framework hooks ─────────────────────────────────────────────────────',
84
+ ' // Both are REQUIRED. The compiler lints for them; a missing hook is',
85
+ ' // re-seeded with the default below and reported loudly.',
86
+ '',
87
+ ' // Top-level `users/{uid}` keys ONLY your backend may write.',
88
+ ' // e.g. return [\'xp\', \'credits\'];',
89
+ ' function protectedFields() {',
90
+ ' return [];',
91
+ ' }',
92
+ '',
93
+ ' // Extra condition ANDed into the framework\'s `users/{uid}` write rule.',
94
+ ' // e.g. return emailVerified();',
95
+ ' function canWriteUser() {',
96
+ ' return emailVerified() && incomingData().keys().hasAny([\'profile\']);',
97
+ ' }',
98
+ ' }',
99
+ '}',
100
+ '',
101
+ ].join('\n');
102
+
103
+ /**
104
+ * The shipped seed with `rules` written into its own rules region.
105
+ * @param {string} [rules]
106
+ * @returns {string}
107
+ */
108
+ function brandSourceWith(rules) {
109
+ const seed = jetpack.read(BRAND_RULES_SEED);
110
+ if (!rules) {
111
+ return seed;
112
+ }
113
+
114
+ const lineEnd = seed.indexOf('\n', seed.indexOf('// ─── Your rules ─'));
115
+
116
+ return `${seed.slice(0, lineEnd + 1)}${rules}\n${seed.slice(lineEnd + 1)}`;
117
+ }
118
+
119
+ function seedTarget(prefix, brandSource) {
120
+ const targetPath = jetpack.tmpDir({ prefix }).path();
121
+
122
+ jetpack.write(path.join(targetPath, 'package.json'), JSON.stringify({ name: 'rules-compile-app', dependencies: {} }, null, 2));
123
+ jetpack.write(path.join(targetPath, 'src', 'index.js'), '// entry\n');
124
+ jetpack.write(path.join(targetPath, 'config', 'omega.json5'), JSON.stringify({
125
+ brand: { name: 'Rules Compile', url: 'https://rules-compile.test' },
126
+ cloud: { config: { projectId: 'demo-rules-compile' } },
127
+ targets: { backend: {} },
128
+ }, null, 2));
129
+ jetpack.write(path.join(targetPath, 'firebase.json'), JSON.stringify({ firestore: { rules: COMPILED_RULES_FILE } }, null, 2));
130
+
131
+ if (brandSource) {
132
+ jetpack.write(path.join(targetPath, 'firestore.rules'), brandSource);
133
+ }
134
+
135
+ return targetPath;
136
+ }
137
+
138
+ function compileSeed() {
139
+ return compileRules({ brandSource: jetpack.read(BRAND_RULES_SEED) }).compiled;
140
+ }
141
+
142
+ module.exports = defineCases({
143
+ description: 'Compiled Firestore rules: two sources, one artifact, merged by match',
144
+ type: 'group',
145
+ timeout: 20000,
146
+
147
+ tests: [
148
+ // The header is the whole clarity requirement: a reader who opens the
149
+ // generated file must learn, without leaving it, that it is generated and
150
+ // WHICH two files to edit instead.
151
+ {
152
+ name: 'compiled-header-names-both-sources-and-forbids-editing',
153
+ auth: 'none',
154
+
155
+ async run({ assert }) {
156
+ const header = compileSeed().split('rules_version')[0];
157
+
158
+ assert.match(header, /GENERATED FILE — DO NOT EDIT/, 'the artifact must say it is generated');
159
+ assert.match(header, /\.\/firestore\.rules/, 'the header must name the BRAND source');
160
+ assert.match(header, /EDIT THAT FILE/, 'the header must say which file to edit instead');
161
+ assert.match(header, /node_modules\/@omega\.js\/backend\/templates\/firestore\.framework\.rules/, 'the header must name the framework half by its install path');
162
+ assert.match(header, new RegExp(`rules schema v${RULES_VERSION.replace(/\./g, '\\.')}`), 'the header must stamp the rules schema version');
163
+ assert.match(header, /MERGED/, 'the header must say that a matching block of yours merges in');
164
+ },
165
+ },
166
+
167
+ // One scope, or the halves cannot call each other's functions: Firestore
168
+ // resolves functions within a match block, and ORs `allow` across sibling
169
+ // blocks (the whole reason #255 exists).
170
+ {
171
+ name: 'both-halves-share-one-documents-scope',
172
+ auth: 'none',
173
+
174
+ async run({ assert }) {
175
+ const compiled = compileRules({ brandSource: brandSourceWith(' function brandOnlyHelper() {\n return true;\n }') }).compiled;
176
+ const body = extractDocumentsBody(compiled, 'compiled');
177
+
178
+ assert.equal(compiled.match(/rules_version/g).length, 1, 'exactly one rules_version declaration');
179
+ assert.equal(compiled.match(/service cloud\.firestore/g).length, 1, 'exactly one service block');
180
+ assert.equal((compiled.match(/match \/databases\/\{database\}\/documents/g) || []).length, 1, 'exactly one documents match block');
181
+ assert.match(body, /function brandOnlyHelper\(\)/, 'a brand function must land in the shared scope');
182
+ assert.match(body, /function isUser\(identity\)/, 'the framework helpers must land in the same scope');
183
+ },
184
+ },
185
+
186
+ // The merge contract (#353), at the string level: the brand's condition
187
+ // ANDs onto the framework's for the op both blocks declare, and the brand's
188
+ // block does NOT also survive as a sibling (a sibling would only widen).
189
+ {
190
+ name: 'a-brand-block-merges-into-the-framework-block-it-matches',
191
+ auth: 'none',
192
+
193
+ async run({ assert }) {
194
+ const { compiled, merged, warnings } = compileRules({
195
+ brandSource: brandSourceWith([
196
+ ' match /users/{uid} {',
197
+ ' allow create, update: if !isWritingAny([\'xp\']) && isEmailVerified();',
198
+ ' }',
199
+ ].join('\n')),
200
+ });
201
+
202
+ assert.deepEqual(merged, ['/users/{uid}'], 'the merged block must be reported');
203
+ assert.deepEqual(warnings, [], 'a same-op merge has nothing to warn about');
204
+ assert.match(
205
+ compiled,
206
+ /allow create, update: if isUser\(uid\) && !isWritingFrameworkField\(\) && \(!isWritingAny\(\['xp'\]\) && isEmailVerified\(\)\);/,
207
+ 'the brand condition must be parenthesized and ANDed onto the framework\'s',
208
+ );
209
+ assert.equal((compiled.match(/match \/users\/\{uid\} \{/g) || []).length, 1, 'the brand block must be MERGED, never left as a widening sibling');
210
+ assert.match(compiled, /allow read: if isUser\(uid\);/, 'an op the brand said nothing about is untouched');
211
+ assert.match(compiled, /⤷ merged with your firestore\.rules/, 'the artifact must mark what merged into what');
212
+ },
213
+ },
214
+
215
+ // Wildcard names are the author's business: blocks pair on the PATH, and
216
+ // the brand's variable is renamed to the framework's inside the fold-in.
217
+ {
218
+ name: 'a-brand-wildcard-name-is-canonicalized-and-renamed',
219
+ auth: 'none',
220
+
221
+ async run({ assert }) {
222
+ const { compiled, merged } = compileRules({
223
+ brandSource: brandSourceWith([
224
+ ' match /users/{userId} {',
225
+ ' allow create, update: if isUser(userId);',
226
+ '',
227
+ ' match /journal/{entryId} {',
228
+ ' allow read: if isUser(userId);',
229
+ ' }',
230
+ ' }',
231
+ ].join('\n')),
232
+ });
233
+
234
+ // The `⤷ merged` marker quotes the brand's block, so only the RULES
235
+ // (never the comments) have to be free of the brand's own name.
236
+ const code = compiled.split('\n').filter((line) => !line.trim().startsWith('//')).join('\n');
237
+
238
+ assert.deepEqual(merged, ['/users/{uid}'], 'the block must merge despite the different wildcard name');
239
+ assert.equal(code.includes('userId'), false, 'no rule may still name the brand\'s own wildcard');
240
+ assert.match(compiled, /allow create, update: if isUser\(uid\) && !isWritingFrameworkField\(\) && \(isUser\(uid\)\);/, 'the folded condition must read the framework\'s variable');
241
+ assert.match(compiled, /match \/journal\/\{entryId\} \{\n\s+allow read: if isUser\(uid\);/, 'a nested match must splice in, renamed');
242
+ },
243
+ },
244
+
245
+ // Everything the framework has no opinion about stays the brand's: a path
246
+ // it never declares passes through, and an op it never declares appends
247
+ // (that op widens, exactly as a sibling block always did). An op that is
248
+ // not the same NAME but covers the same ground — `get` beside the
249
+ // framework's `read` — appends too, and says so out loud.
250
+ {
251
+ name: 'a-brand-only-path-passes-through-and-a-brand-only-op-appends',
252
+ auth: 'none',
253
+
254
+ async run({ assert }) {
255
+ const { compiled, warnings } = compileRules({
256
+ brandSource: brandSourceWith([
257
+ ' match /leaderboards/{id} {',
258
+ ' allow read: if true;',
259
+ ' }',
260
+ '',
261
+ ' match /users/{uid} {',
262
+ ' allow delete: if isUser(uid);',
263
+ ' allow get: if isAdmin();',
264
+ ' }',
265
+ ].join('\n')),
266
+ });
267
+
268
+ const brandSection = compiled.split('Framework rules (@omega.js/backend)')[0];
269
+ const userBlock = compiled.split('match /users/{uid} {')[1].split('\n }')[0];
270
+
271
+ assert.match(brandSection, /match \/leaderboards\/\{id\} \{/, 'a brand-only path stays in the brand section, untouched');
272
+ assert.match(userBlock, /⤷ from your firestore\.rules\n\s+allow delete: if isUser\(uid\);/, 'a brand-only op appends into the merged block');
273
+ assert.match(userBlock, /allow create, update: if isUser\(uid\) && !isWritingFrameworkField\(\);/, 'the framework ops are untouched by an op it does not declare');
274
+ assert.equal(warnings.length, 1, `expected the widening warning, got ${warnings.length}`);
275
+ assert.match(warnings[0], /your `allow get` overlaps the framework's `allow read`/, 'the widen-not-tighten case must be reported, never silent');
276
+
277
+ // The other direction — ONE brand op covering SEVERAL framework ops.
278
+ // The remedy has to name every one of them: obeying `allow create`
279
+ // alone would tighten half the rule and leave `update` widened.
280
+ const { warnings: aliasWarnings } = compileRules({
281
+ brandSource: brandSourceWith([
282
+ ' match /users/{uid} {',
283
+ ' allow write: if isAdmin();',
284
+ ' }',
285
+ ].join('\n')),
286
+ });
287
+
288
+ assert.equal(aliasWarnings.length, 1, `expected the widening warning, got ${aliasWarnings.length}`);
289
+ assert.match(aliasWarnings[0], /your `allow write` overlaps the framework's `allow create, update`/, 'the warning must name every framework op the brand op covers');
290
+ assert.match(aliasWarnings[0], /Meant to tighten\? Write `allow create, update`\./, 'the remedy must name every overlapping op, or obeying it half-tightens');
291
+ },
292
+ },
293
+
294
+ // A framework statement covering several ops splits only as far as it must.
295
+ {
296
+ name: 'a-multi-op-framework-statement-splits-only-for-the-tightened-op',
297
+ auth: 'none',
298
+
299
+ async run({ assert }) {
300
+ const { compiled } = compileRules({
301
+ brandSource: brandSourceWith([
302
+ ' match /payments-carts/{cartId} {',
303
+ ' allow update: if getIncomingData().total < 100;',
304
+ ' }',
305
+ ].join('\n')),
306
+ });
307
+
308
+ const block = compiled.split('match /payments-carts/{uid} {')[1].split('\n }')[0];
309
+
310
+ assert.match(block, /allow create: if isUser\(uid\)[\s\S]*?'pending';/, 'the untightened op keeps the framework condition alone');
311
+ assert.match(block, /allow update: if isUser\(uid\)[\s\S]*?'pending' && \(getIncomingData\(\)\.total < 100\);/, 'only the tightened op carries the brand condition');
312
+ },
313
+ },
314
+
315
+ // Two brand blocks on the SAME canonical path: the second tightens what
316
+ // the first already produced, in the order they were written. The wildcard
317
+ // shape is the one that used to crash — the merge marker quotes the brand's
318
+ // path, braces and all, so a merged block cannot be re-split on its text.
319
+ {
320
+ name: 'two-brand-blocks-on-one-path-both-tighten-in-order',
321
+ auth: 'none',
322
+
323
+ async run({ assert }) {
324
+ const { compiled, merged } = compileRules({
325
+ brandSource: brandSourceWith([
326
+ ' match /users/{userId} {',
327
+ ' allow create, update: if !isWritingAny([\'xp\']);',
328
+ ' }',
329
+ '',
330
+ ' match /users/{uid} {',
331
+ ' allow create, update: if isEmailVerified();',
332
+ ' }',
333
+ ].join('\n')),
334
+ });
335
+
336
+ assert.deepEqual(merged, ['/users/{uid}', '/users/{uid}'], 'both blocks must merge into the same framework block');
337
+ assert.match(
338
+ compiled,
339
+ /allow create, update: if isUser\(uid\) && !isWritingFrameworkField\(\) && \(!isWritingAny\(\['xp'\]\)\) && \(isEmailVerified\(\)\);/,
340
+ 'both brand conditions must AND on, in the order they were written',
341
+ );
342
+ assert.equal((compiled.match(/match \/users\/\{uid\} \{/g) || []).length, 1, 'the two blocks must land in the ONE framework block');
343
+ assert.equal((compiled.match(/⤷ merged with your firestore\.rules/g) || []).length, 2, 'every merge must be marked, not just the last one');
344
+ assert.match(compiled, /allow read: if isUser\(uid\);/, 'an op neither block declared is untouched');
345
+ },
346
+ },
347
+
348
+ // The framework's own user rule declares CREATE and UPDATE by name, and
349
+ // nothing else: `allow write` covered delete too, and every field helper
350
+ // reads incoming data a delete does not carry — so an owner deleting their
351
+ // own user doc was denied by an evaluation ERROR. Naming the two ops the
352
+ // rule actually means leaves delete to the admin catch-all, where it is
353
+ // denied by the rule instead.
354
+ {
355
+ name: 'the-framework-users-rule-declares-create-and-update-only',
356
+ auth: 'none',
357
+
358
+ async run({ assert }) {
359
+ const block = compileSeed().split('match /users/{uid} {')[1].split('\n }')[0];
360
+
361
+ assert.match(block, /allow create, update: if isUser\(uid\) && !isWritingFrameworkField\(\);/, 'the write ops must be named, not spelled `write`');
362
+ assert.match(block, /allow read: if isUser\(uid\);/, 'the read rule is unchanged');
363
+ assert.equal(/allow[^:]*\bwrite\b/.test(block), false, 'no `allow write` may survive — it silently covers delete');
364
+ assert.equal(/allow[^:]*\bdelete\b/.test(block), false, 'and delete is deliberately left to the admin catch-all');
365
+ },
366
+ },
367
+
368
+ // #288: the malformed-doc guard legacy BEM had and the managed block lost.
369
+ {
370
+ name: 'notifications-update-requires-token-to-equal-the-doc-id',
371
+ auth: 'none',
372
+
373
+ async run({ assert }) {
374
+ const compiled = compileSeed();
375
+ const block = compiled.split('match /notifications/{token} {')[1].split(' }')[0];
376
+ const update = block.split('allow update:')[1];
377
+
378
+ assert.match(update, /getIncomingData\(\)\.token == token/, 'update must require the incoming token to equal the doc id');
379
+ assert.match(update, /getIncomingData\(\)\.token == getExistingData\(\)\.token/, 'update must keep the token immutable');
380
+ assert.match(block, /allow get: if true;/, 'get: if true stays by design (token-as-capability)');
381
+ },
382
+ },
383
+
384
+ // Migration off the v2 hook era (#353): a hook still carrying its shipped
385
+ // default is deleted, a hook carrying the brand's own code is KEPT as an
386
+ // ordinary function and reported, and calls to renamed helpers are fixed —
387
+ // a rules file calling a function no half defines does not load.
388
+ {
389
+ name: 'a-hook-era-source-drops-default-hooks-and-keeps-a-customized-one',
390
+ auth: 'none',
391
+
392
+ async run({ assert }) {
393
+ const targetPath = seedTarget('omega-rules-hooks-', HOOK_ERA_SOURCE);
394
+
395
+ const result = ensureBrandRulesSource({ projectDir: targetPath });
396
+ const migrated = jetpack.read(path.join(targetPath, 'firestore.rules'));
397
+
398
+ assert.equal(result.migrated, true, 'the hook era must be detected');
399
+ assert.deepEqual(result.strippedHooks, ['protectedFields'], 'the default-bodied hook must be reported as stripped');
400
+ assert.deepEqual(result.keptHooks, ['canWriteUser'], 'the customized hook must be reported as kept');
401
+
402
+ assert.equal(migrated.includes('function protectedFields('), false, 'the default-bodied hook must be gone');
403
+ assert.match(migrated, /function canWriteUser\(\) \{/, 'the customized hook must survive as a plain function');
404
+ assert.match(migrated, /getIncomingData\(\)\.keys\(\)\.hasAny\(\['profile'\]\)/, 'the brand\'s own condition must survive, with only its renamed calls rewritten');
405
+ assert.match(migrated, /Kept from the retired `canWriteUser\(\)` framework hook/, 'the kept function must say why it is still there');
406
+ assert.match(migrated, /isEmailVerified\(\)/, 'a call to a renamed helper must be renamed with it');
407
+ assert.equal(/\bemailVerified\(\)/.test(migrated.replace(/isEmailVerified/g, '')), false, 'no call to the old name may survive');
408
+
409
+ assert.match(migrated, /match \/leaderboards\/\{id\}/, 'the brand\'s own rules must survive the migration');
410
+ assert.equal(migrated.includes('─── Framework hooks ───'), false, 'the hook section header must go with the hooks');
411
+ assert.equal(migrated.includes('Both are REQUIRED'), false, 'the hook-era instructions must go with them');
412
+ assert.match(migrated, /MERGE-BY-MATCH/, 'the stale header must be replaced with the current one');
413
+
414
+ // Idempotent: a second setup has nothing left to do.
415
+ const second = ensureBrandRulesSource({ projectDir: targetPath });
416
+ assert.equal(second.migrated, false, 'the migration must run once');
417
+ assert.equal(jetpack.read(path.join(targetPath, 'firestore.rules')), migrated, 'a second setup must not touch the file');
418
+
419
+ // …and the question SETTLES. The kept function is the brand's own code
420
+ // now, so a migrated file must stop answering "unmigrated" — otherwise
421
+ // every future setup re-reports it and re-prints the warning forever.
422
+ assert.equal(needsRulesMigration(migrated), false, 'a migrated file must stop reporting as unmigrated');
423
+
424
+ // …and what it produced compiles.
425
+ const { compiled } = compileRules({ brandSource: migrated });
426
+ assert.match(compiled, /match \/leaderboards\/\{id\}/, 'the compiled artifact carries the brand rules');
427
+ assert.match(compiled, /match \/notifications\/\{token\}/, 'the compiled artifact carries the framework rules');
428
+ },
429
+ },
430
+
431
+ // Migration: a pre-#255 file converts ONCE, custom region intact, markers
432
+ // gone.
433
+ {
434
+ name: 'legacy-marker-file-migrates-once-and-keeps-the-custom-region',
435
+ auth: 'none',
436
+
437
+ async run({ assert }) {
438
+ const targetPath = seedTarget('omega-rules-legacy-', LEGACY_SOURCE);
439
+
440
+ const first = ensureBrandRulesSource({ projectDir: targetPath });
441
+ const migrated = jetpack.read(path.join(targetPath, 'firestore.rules'));
442
+
443
+ assert.equal(first.migrated, true, 'the legacy marker block must be detected');
444
+ assert.match(migrated, /match \/leaderboards\/\{id\}/, 'the brand\'s custom region must be preserved');
445
+ assert.equal(migrated.includes('OMEGA Rules (v'), false, 'the managed marker block must be gone');
446
+ assert.equal(migrated.includes('End OMEGA Rules'), false, 'the closing marker must be gone too');
447
+ assert.equal(migrated.includes('function protectedFields('), false, 'the migration must seed no hooks — they are retired');
448
+
449
+ const second = ensureBrandRulesSource({ projectDir: targetPath });
450
+ assert.equal(second.migrated, false, 'migration must run once');
451
+ assert.equal(jetpack.read(path.join(targetPath, 'firestore.rules')), migrated, 'a second setup must not touch the file');
452
+
453
+ // The migrated file still compiles, and the framework half comes back.
454
+ const compiled = compileRules({ brandSource: migrated }).compiled;
455
+ assert.match(compiled, /match \/leaderboards\/\{id\}/, 'the compiled artifact carries the brand rules');
456
+ assert.match(compiled, /match \/notifications\/\{token\}/, 'the compiled artifact carries the framework rules');
457
+ },
458
+ },
459
+
460
+ // …and until that migration runs, the compile REFUSES. A marker file still
461
+ // carries the framework's own functions, so splicing it into the framework
462
+ // half emits every one of them twice — a ruleset Firestore will not load.
463
+ {
464
+ name: 'a-legacy-marker-source-is-refused-instead-of-compiled',
465
+ auth: 'none',
466
+
467
+ async run({ assert }) {
468
+ const targetPath = seedTarget('omega-rules-refuse-', LEGACY_SOURCE);
469
+ const warnings = [];
470
+
471
+ const result = compileFirestoreRules({ projectDir: targetPath, onWarn: (message) => warnings.push(message) });
472
+
473
+ assert.equal(result.refused, true, 'the build must report the refusal');
474
+ assert.equal(jetpack.exists(path.join(targetPath, COMPILED_RULES_FILE)), false, 'an unmigrated source must leave no artifact behind');
475
+ assert.equal(warnings.length, 1, `expected one warning, got ${warnings.length}`);
476
+ assert.match(warnings[0], /legacy OMEGA Rules marker block/, 'the refusal must name what it found');
477
+ assert.match(warnings[0], /npx omega (test|migrate:rules)/, 'the refusal must name the command that moves the tree forward');
478
+
479
+ // The pure compile refuses at the break point too, so no other caller
480
+ // can talk it into the duplicate-function artifact.
481
+ let threw = null;
482
+ try {
483
+ compileRules({ brandSource: LEGACY_SOURCE });
484
+ } catch (error) {
485
+ threw = error;
486
+ }
487
+
488
+ assert.ok(threw, 'compiling an unmigrated source must throw');
489
+ assert.match(threw.message, /npx omega migrate:rules/, 'the error must name the run-alone migration verb');
490
+
491
+ // The STAGE only reports it, because setup stages before its checks
492
+ // run — a throw here would kill the very run that migrates the file.
493
+ const { staged } = stageFunctions({ projectDir: targetPath });
494
+
495
+ assert.equal(staged.some((step) => step.includes('firestore.rules')), false, 'the stage must not claim a compile it refused');
496
+ assert.equal(jetpack.exists(path.join(targetPath, COMPILED_RULES_FILE)), false, 'and it must still leave no artifact');
497
+ },
498
+ },
499
+
500
+ // The build step: every stage rebuilds the artifact, because the stage
501
+ // wipes dist/ and firebase.json points at what is left behind.
502
+ {
503
+ name: 'every-stage-recompiles-the-artifact-from-the-brand-source',
504
+ auth: 'none',
505
+
506
+ async run({ assert }) {
507
+ const targetPath = seedTarget('omega-rules-stage-', jetpack.read(BRAND_RULES_SEED));
508
+ const artifact = path.join(targetPath, COMPILED_RULES_FILE);
509
+
510
+ const { staged } = stageFunctions({ projectDir: targetPath });
511
+ assert.equal(staged.some((step) => step.includes('firestore.rules')), true, 'the stage must report the compile step');
512
+ assert.equal(jetpack.exists(artifact), 'file', 'the stage must write the compiled artifact');
513
+
514
+ // A brand-source edit reaches the artifact on the next stage — this is
515
+ // what the watch does when firestore.rules changes.
516
+ const source = path.join(targetPath, 'firestore.rules');
517
+ jetpack.write(source, brandSourceWith(' match /posts/{id} {\n allow read: if true;\n }'));
518
+ stageFunctions({ projectDir: targetPath });
519
+
520
+ assert.equal(jetpack.read(artifact).includes('match /posts/{id} {'), true, 'a brand-source edit must recompile');
521
+ },
522
+ },
523
+
524
+ // Nothing reads a compiled artifact firebase.json does not name.
525
+ {
526
+ name: 'firebase-json-targets-the-compiled-artifact',
527
+ auth: 'none',
528
+
529
+ async run({ assert }) {
530
+ const template = jetpack.read(path.join(TEMPLATES_DIR, 'firebase.json'), 'json');
531
+ const fixture = jetpack.read(path.join(FIXTURE_DIR, 'firebase.json'), 'json');
532
+
533
+ assert.equal(template.firestore.rules, COMPILED_RULES_FILE, 'the shipped firebase.json must point at the compiled artifact');
534
+ assert.equal(fixture.firestore.rules, COMPILED_RULES_FILE, 'the self-test fixture must point at the compiled artifact');
535
+ },
536
+ },
537
+
538
+ // A stale (pre-#255) firebase.json would boot the emulator on the brand
539
+ // half alone — every framework rule silently gone. The build refuses to be
540
+ // quiet about it.
541
+ {
542
+ name: 'a-stale-firebase-json-target-is-reported-loudly',
543
+ auth: 'none',
544
+
545
+ async run({ assert }) {
546
+ const targetPath = seedTarget('omega-rules-stale-', jetpack.read(BRAND_RULES_SEED));
547
+ const warnings = [];
548
+
549
+ jetpack.write(path.join(targetPath, 'firebase.json'), JSON.stringify({ firestore: { rules: 'firestore.rules' } }, null, 2));
550
+ compileFirestoreRules({ projectDir: targetPath, onWarn: (message) => warnings.push(message) });
551
+
552
+ assert.equal(warnings.length, 1, `expected one warning, got ${warnings.length}`);
553
+ assert.match(warnings[0], /firebase\.json points firestore\.rules at "firestore\.rules"/, 'the warning must name the stale target');
554
+ // Setup DEFERS on this tree ([#522](https://github.com/Omega-JS-Stack/omega/issues/522)) —
555
+ // the warning has to name the command that actually moves it.
556
+ assert.ok(warnings[0].includes(RULES_MIGRATION_COMMAND), `the warning must say how to fix it (${RULES_MIGRATION_COMMAND})`);
557
+ },
558
+ },
559
+
560
+ // The brand source is a teaching surface: it has to tell a brand how the
561
+ // merge works and which helpers it may call.
562
+ {
563
+ name: 'the-seeded-brand-source-teaches-the-merge-and-the-helpers',
564
+ auth: 'none',
565
+
566
+ async run({ assert }) {
567
+ const seed = jetpack.read(BRAND_RULES_SEED);
568
+
569
+ assert.equal(seed.includes('OMEGA Rules'), false, 'the seed must carry no managed marker block');
570
+ assert.match(seed, /templates\/firestore\.framework\.rules/, 'the seed must point at the framework half');
571
+ assert.match(seed, /MERGE-BY-MATCH/, 'the seed must teach the merge model');
572
+ assert.match(seed, /allow create, update: if isUser\(uid\) && !isWritingFrameworkField\(\) && \(!isWritingAny\(\['xp'\]\) && isEmailVerified\(\)\);/, 'the seed must carry the worked example of a merge');
573
+ for (const helper of ['isUser', 'isAdmin', 'isAuthenticated', 'getAuthUid', 'getAuthEmail', 'getRoles', 'getExistingData', 'getIncomingData', 'isWritingField', 'isWritingAny', 'isOwner', 'isEmailVerified']) {
574
+ assert.match(seed, new RegExp(`${helper}\\(`), `the seed must name the ${helper}() helper as callable`);
575
+ }
576
+ assert.match(seed, /TOP-LEVEL: protecting `xp\.total` means listing `'xp'`/, 'the seed must warn that the field list is top-level');
577
+ },
578
+ },
579
+
580
+ // The rename sweep (#353): no retired name survives on a RULES surface —
581
+ // the two shipped halves, the artifact they compile to, and the CLI code
582
+ // that writes them. It covers every retirement in one list, so settling the
583
+ // API a second time (`belongsTo` → `isUser`, the value helpers onto `get*`)
584
+ // extends the gate by extending the migration map. Deliberately not a
585
+ // whole-tree grep: `emailVerified` is also a Firebase Auth user-record
586
+ // property and `existingData` an ordinary variable name all over the
587
+ // backend (different namespaces entirely), and the docs and these suites
588
+ // have to name the retired symbols to explain the migration. The compiler
589
+ // is exempt for the same reason — migrating those names off a consumer's
590
+ // file is its job.
591
+ {
592
+ name: 'no-retired-name-survives-the-rename-sweep',
593
+ auth: 'none',
594
+
595
+ async run({ assert }) {
596
+ const exempt = [path.join(PACKAGE_DIR, 'dist', 'cli', 'utils', 'compile-rules.js')];
597
+ const files = [
598
+ ...jetpack.find(TEMPLATES_DIR, { matching: '*.rules' }).map((file) => path.resolve(file)),
599
+ ...jetpack.find(path.join(PACKAGE_DIR, 'dist', 'cli'), { matching: '*.js' }).map((file) => path.resolve(file)),
600
+ ].filter((file) => !exempt.includes(file));
601
+
602
+ const offenders = [];
603
+ for (const file of files) {
604
+ const contents = jetpack.read(file);
605
+ for (const name of RETIRED_NAMES) {
606
+ if (new RegExp(`\\b${name}\\b`).test(contents)) {
607
+ offenders.push(`${path.relative(PACKAGE_DIR, file)}: ${name}`);
608
+ }
609
+ }
610
+ }
611
+
612
+ assert.deepEqual(offenders, [], `retired names still in the tree: ${offenders.join(', ')}`);
613
+
614
+ // …and the artifact a consumer deploys names none of them either.
615
+ const compiled = compileSeed();
616
+ for (const name of RETIRED_NAMES) {
617
+ assert.equal(new RegExp(`\\b${name}\\b`).test(compiled), false, `the compiled ruleset must not name ${name}`);
618
+ }
619
+ },
620
+ },
621
+ ],
622
+ });