@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,1404 @@
1
+ // Libraries
2
+ const path = require('path');
3
+ const { get: _get, set: _set } = require('lodash');
4
+ const jetpack = require('fs-jetpack');
5
+ const { hasOmegaConfig, loadConfig, loadEnv, formatErrors, backendProjectType } = require('../vendor/config/index.js');
6
+ const { resolvedConfigValues } = require('./helpers/resolved-config.js');
7
+ const env = require('./libraries/env.js');
8
+ const EventEmitter = require('events');
9
+ // const EventEmitter = require('events').EventEmitter;
10
+ const util = require('util');
11
+
12
+ // const { debug, log, error, warn } = require('firebase-functions/lib/logger');
13
+ // let User;
14
+ // let Analytics;
15
+ // Paths
16
+ const wrappers = './functions/wrappers';
17
+ const _legacy = './functions/_legacy';
18
+ const events = path.resolve(__dirname, './events');
19
+ const cron = path.resolve(events, './cron');
20
+
21
+ const BEM_TEMPLATES_DIR = path.resolve(__dirname, '../../templates');
22
+ const BEM_PACKAGE = require('../../package.json');
23
+
24
+ function Manager() {
25
+ const self = this;
26
+
27
+ // @omega.js/backend library version
28
+ self.version = BEM_PACKAGE.version;
29
+
30
+ // Constants
31
+ self.SERVER_UUID = '11111111-1111-1111-1111-111111111111';
32
+
33
+ // Modable
34
+ self.libraries = {};
35
+ self.handlers = {};
36
+
37
+ self._internal = {
38
+ storage: {},
39
+ };
40
+
41
+ self.interface = {}
42
+
43
+ // Setup EventEmitter
44
+ EventEmitter.call(self);
45
+
46
+ // Return
47
+ return self;
48
+ }
49
+
50
+ // Inherit from EventEmitter
51
+ util.inherits(Manager, EventEmitter);
52
+
53
+ // Process-level latch for the TEST-environment banner. init() can run more than
54
+ // once in a single process (the test runner, a custom server, a re-entrant boot);
55
+ // the banner is boot information, not per-init information, so it says its piece
56
+ // once and then stays quiet.
57
+ let _testBannerLogged = false;
58
+
59
+ // The emulator boots a FRESH functions worker per invocation — measured on one
60
+ // playground seed: 53 worker processes for 92 invocations, so a once-per-process
61
+ // line still prints 53 times to announce what the emulator itself announced. The
62
+ // test-environment boot lines are therefore silent under the emulator. They stay
63
+ // LOUD (once) in a deployed process that resolves test mode, which is the case
64
+ // where "this is a test environment" is an alarm, not a truism.
65
+ function isUnderEmulator() {
66
+ return process.env.FUNCTIONS_EMULATOR === 'true';
67
+ }
68
+
69
+ Manager.prototype.init = function (exporter, options) {
70
+ const self = this;
71
+
72
+ // Auto-detect test-runner context. The test runner sets OMEGA_TEST_RUNNER=1
73
+ // before invoking anything that loads @omega.js/backend. When detected, init() runs the
74
+ // library-loading + project-config-setup pieces normally, but skips wiring
75
+ // Firebase Cloud Functions handlers and the custom-server boot (neither
76
+ // works outside an actual Functions runtime). The runner has already called
77
+ // firebase-admin.initializeApp() so we also skip that step to avoid the
78
+ // "default app already initialized" crash.
79
+ const isTestRunner = !!process.env.OMEGA_TEST_RUNNER;
80
+
81
+ // Set options defaults
82
+ options = options || {};
83
+ options.initialize = typeof options.initialize === 'undefined' ? !isTestRunner : options.initialize;
84
+ options.log = typeof options.log === 'undefined' ? false : options.log;
85
+ // projectType (firebase | custom) is resolved AFTER the config load below —
86
+ // the brand's own omega.json5 is its home (`targets.backend.projectType`,
87
+ // #584), so a custom backend needs no init flag a brand has to remember. An
88
+ // explicit option passed here still wins; until then it stays undefined.
89
+ options.routes = typeof options.routes === 'undefined' ? '/routes' : options.routes;
90
+ options.schemas = typeof options.schemas === 'undefined' ? '/schemas' : options.schemas;
91
+ options.setupFunctions = typeof options.setupFunctions === 'undefined' ? !isTestRunner : options.setupFunctions;
92
+ options.setupFunctionsLegacy = typeof options.setupFunctionsLegacy === 'undefined' ? false : options.setupFunctionsLegacy;
93
+ options.setupFunctionsIdentity = typeof options.setupFunctionsIdentity === 'undefined' ? !isTestRunner : options.setupFunctionsIdentity;
94
+ options.setupServer = typeof options.setupServer === 'undefined' ? !isTestRunner : options.setupServer;
95
+ options.initializeLocalStorage = typeof options.initializeLocalStorage === 'undefined' ? false : options.initializeLocalStorage;
96
+ options.resourceZone = typeof options.resourceZone === 'undefined' ? 'us-central1' : options.resourceZone;
97
+ options.sentry = typeof options.sentry === 'undefined' ? !isTestRunner : options.sentry;
98
+ options.reportErrorsInDev = typeof options.reportErrorsInDev === 'undefined' ? false : options.reportErrorsInDev;
99
+ options.firebaseConfig = options.firebaseConfig;
100
+ options.useFirebaseLogger = typeof options.useFirebaseLogger === 'undefined' ? true : options.useFirebaseLogger;
101
+ options.serviceAccountPath = typeof options.serviceAccountPath === 'undefined' ? 'service-account.json' : options.serviceAccountPath;;
102
+ options.fetchStats = typeof options.fetchStats === 'undefined'
103
+ // ? options.projectType === 'firebase'
104
+ ? false
105
+ : options.fetchStats;
106
+ options.checkNodeVersion = typeof options.checkNodeVersion === 'undefined' ? true : options.checkNodeVersion;
107
+ options.uniqueAppName = options.uniqueAppName || undefined;
108
+ options.ctx = options.ctx || {};
109
+ options.cwd = typeof options.cwd === 'undefined' ? process.cwd() : options.cwd;
110
+ options.projectPackageDirectory = typeof options.projectPackageDirectory === 'undefined' ? undefined : options.projectPackageDirectory;
111
+ options.logSavePath = typeof options.logSavePath === 'undefined' ? false : options.logSavePath;
112
+ // options.ctx.optionsLogString = options.ctx.optionsLogString || undefined;
113
+
114
+ // Express options
115
+ options.express = options.express || {};
116
+ options.express.bodyParser = options.express.bodyParser || {};
117
+ options.express.bodyParser.json = options.express.bodyParser.json || { limit: '100kb' };
118
+ options.express.bodyParser.urlencoded = options.express.bodyParser.urlencoded || { limit: '100kb', extended: true };
119
+
120
+ // Load libraries
121
+ self.libraries = {
122
+ // Third-party
123
+ functions: null, // firebase-functions, loaded once projectType resolves (#584)
124
+ admin: require('firebase-admin'),
125
+ cors: require('cors')({ origin: true }),
126
+ sentry: null,
127
+
128
+ // First-party
129
+ RouteContext: require('./helpers/context/index.js'),
130
+ localDatabase: null,
131
+ User: null,
132
+ Analytics: null,
133
+ logger: null,
134
+ };
135
+
136
+ // Set properties
137
+ self.cwd = options.cwd;
138
+ self.rootDirectory = __dirname;
139
+
140
+ // Set options
141
+ self.options = options;
142
+ self.project = options.firebaseConfig || JSON.parse(process.env.FIREBASE_CONFIG || '{}');
143
+ self.project.resourceZone = options.resourceZone;
144
+ self.project.serviceAccountPath = path.resolve(self.cwd, options.serviceAccountPath);
145
+
146
+ // Load package.json
147
+ self.package = resolveProjectPackage(options.projectPackageDirectory || self.cwd);
148
+
149
+ // Resolve the .env cascade from the functions dir (functions/.env rides
150
+ // the deploy artifact; the brand/company layers exist only in local dev)
151
+ try {
152
+ loadEnv(self.cwd);
153
+ } catch (e) {
154
+ self.ctx.error(new Error(`Failed to set up environment variables from .env file: ${e.message}`));
155
+ }
156
+
157
+ // Load config — the consumer's config/omega.json5 resolved through
158
+ // @omega.js/config (brand-monorepo aware: cwd is the functions dir, the
159
+ // loader walks up to the brand layer when one exists). The framework
160
+ // defaults layer is templates/config/omega.json5 resolved through the SAME
161
+ // loader, so both sides live in one shape. Missing consumer config
162
+ // (non-consumer cwd, some tests) → defaults only, same as before the flip.
163
+ const configDefaults = loadConfig(BEM_TEMPLATES_DIR, 'backend').config;
164
+ delete configDefaults.targets;
165
+
166
+ // A consumer omega.json5 is what makes this process a BRAND's backend —
167
+ // the env guard below is advisory without one (framework fixture, #581)
168
+ const hasConsumerConfig = hasOmegaConfig(self.cwd);
169
+
170
+ if (hasConsumerConfig) {
171
+ const { config, errors } = loadConfig(self.cwd, 'backend', { defaults: configDefaults });
172
+ self.config = config;
173
+
174
+ // Boot warns on schema findings, audit (the target checks) throws — the two-mode
175
+ // contract from @omega.js/config. Secrets in the file already threw above.
176
+ if (errors.length) {
177
+ console.warn(`[@omega.js/backend] config/omega.json5 schema warnings:\n${formatErrors(errors)}`);
178
+ }
179
+ } else {
180
+ self.config = configDefaults;
181
+ }
182
+
183
+ // How this backend RUNS (#584): Cloud Functions, or the same app listening
184
+ // on PORT for a container host. The brand's config is the switch —
185
+ // `targets.backend.projectType`, resolved onto the top level here — and an
186
+ // explicit init option still wins for a caller that means to override it.
187
+ // firebase-functions is loaded only for the mode that has functions.
188
+ options.projectType = options.projectType || backendProjectType(self.config);
189
+ self.libraries.functions = options.projectType === 'firebase' ? require('firebase-functions/v1') : null;
190
+
191
+ // Config-DERIVED values, on the config object consumer code already reads
192
+ // (#290): `config.resolved.github.repo` and whatever joins it. The recipes
193
+ // live in @omega.js/config — private, so a brand target cannot call them and
194
+ // used to re-implement them — and the framework runs them once, here, on the
195
+ // composed config.
196
+ self.config.resolved = resolvedConfigValues(self.config);
197
+
198
+ // Expose config on the constructor for static access by internal libraries.
199
+ // Since Node.js caches require(), any `require('./index.js')` returns this same
200
+ // Manager function with .config already set — no need for setConfig() patterns.
201
+ Manager.config = self.config;
202
+
203
+ // Set PAYPAL_CLIENT_ID from config (clientId is public, not a secret — lives in config, not .env)
204
+ process.env.PAYPAL_CLIENT_ID = process.env.PAYPAL_CLIENT_ID || self.config?.payment?.providers?.paypal?.clientId || '';
205
+
206
+ // Set CHARGEBEE_SITE from config (site is public, not a secret — lives in config, not .env)
207
+ process.env.CHARGEBEE_SITE = process.env.CHARGEBEE_SITE || self.config?.payment?.providers?.chargebee?.site || '';
208
+
209
+ // Get brand ID
210
+ const brandId = self.config?.brand?.id;
211
+
212
+ // Set log
213
+ if (options.logSavePath) {
214
+ self.libraries.logger = new (require('wonderful-log'))({
215
+ console: {
216
+ enabled: false,
217
+ },
218
+ file: {
219
+ enabled: true,
220
+ path: options.logSavePath,
221
+ },
222
+ });
223
+ }
224
+
225
+ // Environment helpers — the Manager is the SINGLE SOURCE OF TRUTH (mirrors EM/UJM/BXM,
226
+ // where the Manager owns these). The resolution itself lives in the env reader
227
+ // (libraries/env.js, the ONLY place that reads the raw OMEGA_TEST_MODE /
228
+ // ENVIRONMENT / FUNCTIONS_EMULATOR / TERM_PROGRAM vars) because the provider
229
+ // libraries need the same answer with no Manager handle (#586's dev/live
230
+ // payment split); the three is*() checks derive from it live on every call.
231
+ // They return exactly ONE of three mutually-exclusive values — testing wins,
232
+ // then production, else development.
233
+ // The ctx exposes the same methods but FORWARDS to these (ctx.isTesting()
234
+ // → Manager.isTesting()), so request handlers can keep calling `ctx.*`.
235
+ // Defined BEFORE the ctx is constructed so the ctx's own init() can call back.
236
+ self.getEnvironment = function() {
237
+ return env.environment();
238
+ };
239
+
240
+ // The three checks are mutually exclusive — each true for ONLY its own environment.
241
+ // isDevelopment() is NOT true in testing; isProduction() is a real positive check
242
+ // (never `!isDevelopment()`). Gate "anything non-production" with `!isProduction()`
243
+ // or `isDevelopment() || isTesting()` intentionally.
244
+ self.isDevelopment = function() {
245
+ return self.getEnvironment() === 'development';
246
+ };
247
+ self.isProduction = function() {
248
+ return self.getEnvironment() === 'production';
249
+ };
250
+ self.isTesting = function() {
251
+ return self.getEnvironment() === 'testing';
252
+ };
253
+
254
+ // Boot guard for every REQUIRED env key (#581, superseding #569's
255
+ // production-only unsubscribe-key branch). A process without one serves
256
+ // every route fine and then crashes at the first customer action that needs
257
+ // it — a real customer's order email, in the case that started this — so a
258
+ // brand's backend refuses to boot instead, in every environment: the keys
259
+ // are one `npx omega manage` away, and a dev loop that boots without them
260
+ // only moves the crash downstream. The one advisory lane is a process with
261
+ // no consumer config at all (the framework's own fixture), which says the
262
+ // fault out loud and continues.
263
+ try {
264
+ env.assertRequired('backend');
265
+ } catch (e) {
266
+ if (!env.guardIsAdvisory({ hasConsumerConfig })) { throw e; }
267
+ console.warn(`[@omega.js/backend:index] ${e.message}`);
268
+ }
269
+
270
+ // The other half of the boot guard (#626): the keys this brand's OWN config
271
+ // made mandatory (the schema's `requiredWhen` rules — a configured GA4 stream
272
+ // with no Measurement Protocol secret, a reCAPTCHA site key with no secret
273
+ // half). A deployed backend REFUSES: those are the runs where the silence is
274
+ // a customer's. Every other environment says it once and continues, because
275
+ // a half-configured local loop is a normal step on the way to a full one.
276
+ try {
277
+ env.assertRules(self.config, 'backend');
278
+ } catch (e) {
279
+ if (env.environment() === 'production') { throw e; }
280
+ console.warn(`[@omega.js/backend:index] ${e.message}`);
281
+ }
282
+
283
+ // Init ctx
284
+ self.ctx = self.RouteContext().init({
285
+ req: null,
286
+ res: null,
287
+ admin: self.libraries.admin,
288
+ functions: self.libraries.functions,
289
+ Manager: self,
290
+ }, options.ctx);
291
+
292
+ // Helper functions for URLs based on environment
293
+ self.getFunctionsUrl = function(env) {
294
+ // Auto-detect (no explicit env): development OR testing → local URLs. Test runs
295
+ // hit the local emulator, so getApiUrl/getFunctionsUrl/getWebsiteUrl must resolve
296
+ // to localhost. NOTE: getParentApiUrl/getParentUrl are intentionally NOT changed —
297
+ // the parent is a real remote server with no localhost equivalent.
298
+ const isDev = env === 'development' || (!env && (self.isDevelopment() || self.isTesting()));
299
+ // N7: the CLI that booted the stack publishes resolved ports via
300
+ // OMEGA_*_PORT env (functions workers inherit them) — classic default
301
+ // when unset (plain local boot).
302
+ return isDev
303
+ ? `http://localhost:${process.env.OMEGA_FUNCTIONS_PORT || 5001}/${self.project.projectId}/${self.project.resourceZone}`
304
+ : `https://${self.project.resourceZone}-${self.project.projectId}.cloudfunctions.net`;
305
+ };
306
+
307
+ self.getApiUrl = function(env) {
308
+ // Auto-detect (no explicit env): development OR testing → local URLs. Test runs
309
+ // hit the local emulator, so getApiUrl/getFunctionsUrl/getWebsiteUrl must resolve
310
+ // to localhost. NOTE: getParentApiUrl/getParentUrl are intentionally NOT changed —
311
+ // the parent is a real remote server with no localhost equivalent.
312
+ const isDev = env === 'development' || (!env && (self.isDevelopment() || self.isTesting()));
313
+ if (isDev) {
314
+ const httpsPort = process.env.OMEGA_HTTPS_PORT;
315
+ return httpsPort
316
+ ? `https://localhost:${httpsPort}`
317
+ : `http://localhost:${process.env.OMEGA_HOSTING_PORT || 5002}`;
318
+ }
319
+ return `https://api.${(self.config.brand?.url || '').replace(/^https?:\/\//, '')}`;
320
+ };
321
+
322
+ self.getWebsiteUrl = function(env) {
323
+ // Auto-detect (no explicit env): development OR testing → local URLs. Test runs
324
+ // hit the local emulator, so getApiUrl/getFunctionsUrl/getWebsiteUrl must resolve
325
+ // to localhost. NOTE: getParentApiUrl/getParentUrl are intentionally NOT changed —
326
+ // the parent is a real remote server with no localhost equivalent.
327
+ const isDev = env === 'development' || (!env && (self.isDevelopment() || self.isTesting()));
328
+ // Scheme follows the local https stack (cp176): ONE mkcert install fronts
329
+ // backend AND web dev alike, so this process's own proxy presence
330
+ // (OMEGA_HTTPS_PORT) is the honest signal for the website's scheme too —
331
+ // --no-https / missing mkcert drops both sides back to plain http.
332
+ const websiteScheme = process.env.OMEGA_HTTPS_PORT ? 'https' : 'http';
333
+ return isDev
334
+ ? `${websiteScheme}://localhost:${process.env.OMEGA_WEBSITE_PORT || 4000}`
335
+ : self.config.brand?.url || '';
336
+ };
337
+
338
+ // Resolve the parent @omega.js/backend's website URL (the parent's brand domain, NO `api.` subdomain).
339
+ // - If config.parent === 'self', THIS @omega.js/backend is the parent — returns this brand's own URL.
340
+ // - If config.parent is a URL, returns it as-is.
341
+ // - Returns '' if neither is configured.
342
+ // Use getParentApiUrl() for the API URL (with `api.` subdomain inserted).
343
+ self.getParentUrl = function() {
344
+ const parent = self.config.parent;
345
+ if (parent === 'self') {
346
+ return self.config.brand?.url || '';
347
+ }
348
+ return parent || '';
349
+ };
350
+
351
+ // Resolve the parent @omega.js/backend's API URL (`https://api.{parent-host}`).
352
+ // ALWAYS returns the live production URL — even when THIS brand is running
353
+ // in dev/test mode. The parent's API is a real remote server (no localhost
354
+ // equivalent), so dev-mode does NOT redirect to localhost the way getApiUrl()
355
+ // does. Use this when you need to call the parent's API from any environment.
356
+ self.getParentApiUrl = function() {
357
+ const base = self.getParentUrl().replace(/^https?:\/\//, '');
358
+ return base ? `https://api.${base}` : '';
359
+ };
360
+
361
+ // Returns true when this @omega.js/backend IS the parent (config.parent === 'self').
362
+ // Gates parent-only routes like /marketing/webhook/forward.
363
+ self.isParent = function() {
364
+ return self.config.parent === 'self';
365
+ };
366
+
367
+ // Set more properties (need to wait for ctx to determine if DEV)
368
+ self.project.functionsUrl = self.getFunctionsUrl();
369
+
370
+ // Set API URL (like @omega.js/client's getApiUrl)
371
+ // Testing: http://localhost:5002 (hosting emulator with rewrites)
372
+ // Development: http://localhost:5002 (local hosting)
373
+ // Production: https://api.{domain}
374
+ self.project.apiUrl = self.getApiUrl();
375
+
376
+ // Set website URL
377
+ // Development: http://localhost:4000 (local `omega dev` hosting)
378
+ // Production: https://{domain} (from brand.url)
379
+ self.project.websiteUrl = self.getWebsiteUrl();
380
+
381
+ // Set environment
382
+ process.env.ENVIRONMENT = process.env.ENVIRONMENT || self.getEnvironment();
383
+
384
+ // Set @omega.js/backend env variables
385
+ process.env.OMEGA_FUNCTIONS_URL = self.project.functionsUrl;
386
+ process.env.OMEGA_API_URL = self.project.apiUrl;
387
+ process.env.OMEGA_WEBSITE_URL = self.project.websiteUrl;
388
+
389
+ // Use the working Firebase logger that they disabled for whatever reason
390
+ // Load the Firebase logger compat shim only in production (NOT development or testing).
391
+ if (
392
+ process.env.GCLOUD_PROJECT
393
+ && self.isProduction()
394
+ && options.useFirebaseLogger
395
+ ) {
396
+ // require('firebase-functions/lib/logger/compat'); // Old way
397
+ require('firebase-functions/logger/compat'); // firebase-functions@4 and above?
398
+ }
399
+
400
+ // Handle test environment
401
+ if (self.isTesting()) {
402
+ if (!isUnderEmulator() && !_testBannerLogged) {
403
+ _testBannerLogged = true;
404
+ self.ctx.log('⚠️⚠️⚠️ Running in TEST environment, some features may be disabled ⚠️⚠️⚠️');
405
+ }
406
+
407
+ // Install the test-mode-file watcher exactly once. Lets the test command
408
+ // flip env vars (currently just TEST_EXTENDED_MODE) on the running emulator
409
+ // mid-session without restarting it. See src/test/utils/test-mode-file.js
410
+ // for the file format and allowlist.
411
+ setupTestModeWatcher(self);
412
+ }
413
+
414
+ // Handle dev environments
415
+ if (self.isDevelopment()) {
416
+ const version = require('wonderful-version');
417
+ const nodeUsing = version.major(process.versions.node);
418
+ const nodeRequired = version.major(self.package?.engines?.node || '0.0.0');
419
+
420
+ // Fix firebase-tools overwriting console.log
421
+ // https://stackoverflow.com/questions/56026747/firebase-console-log-on-localhost
422
+ if (process.env.GCLOUD_PROJECT) {
423
+ function logFix() {
424
+ console.error(...arguments);
425
+ }
426
+ console.log = logFix;
427
+ console.info = logFix;
428
+ }
429
+
430
+ // Reject if we're using an unsupported Node.js version
431
+ if (version.is(nodeUsing, '<', nodeRequired)) {
432
+ const msg = `Node.js version mismatch: using ${nodeUsing} but asked for ${nodeRequired}`;
433
+ if (options.checkNodeVersion) {
434
+ self.ctx.error(new Error(msg));
435
+ return process.exit(1);
436
+ } else {
437
+ self.ctx.log(msg);
438
+ }
439
+ }
440
+ }
441
+
442
+ if (options.log) {
443
+ // self.ctx.log('process.env', process.env)
444
+ self.ctx.log('Resolved serviceAccountPath', self.project.serviceAccountPath);
445
+ }
446
+
447
+ if (!brandId) {
448
+ self.ctx.warn('⚠️ Missing config.brand.id');
449
+ }
450
+
451
+ // Setup sentry — @omega.js/monitoring owns the policy (config resolution from
452
+ // `monitoring.providers.sentry.*`, the release tag, the gates) for every OMEGA
453
+ // target (#380).
454
+ // The gates run at BOOT, not per event: getEnvironment() is env-derived and
455
+ // stable for the life of a process, so a non-production run that would have
456
+ // dropped every event in beforeSend now never loads @sentry/node at all.
457
+ // `libraries.sentry` stays the ONE capture handle (null when off) — the
458
+ // chokepoint in helpers/context/respond.js reads it exactly as before.
459
+ if (self.options.sentry) {
460
+ self.libraries.sentry = require('../vendor/monitoring/node.js').initialize({
461
+ config: self.config?.monitoring,
462
+ release: { id: brandId || self.project.projectId, version: self.package.version },
463
+ isProduction: self.isProduction(),
464
+ allowInDev: self.options.reportErrorsInDev,
465
+ // Read at capture time: one process serves many invocations, so the
466
+ // function identity belongs to the event, not the boot.
467
+ tags: () => ({
468
+ 'function.name': self.ctx.meta.name,
469
+ 'function.type': self.ctx.meta.type,
470
+ 'environment': self.getEnvironment(),
471
+ }),
472
+ });
473
+ }
474
+
475
+ // Setup options features
476
+ if (self.options.initialize) {
477
+ // Initialize Firebase. On any managed runtime — explicit ADC pointer, deployed Cloud
478
+ // Functions/Cloud Run (K_SERVICE/FUNCTION_TARGET), or the emulator — a no-args
479
+ // initializeApp() authenticates with the runtime's own identity. A staged
480
+ // service-account.json is ONLY for local scripts hitting the real project.
481
+ const onCloudRuntime = !!process.env.K_SERVICE || !!process.env.FUNCTION_TARGET;
482
+ const onEmulator = process.env.FUNCTIONS_EMULATOR === 'true';
483
+
484
+ if (process.env.GOOGLE_APPLICATION_CREDENTIALS || onCloudRuntime || onEmulator) {
485
+ self.libraries.initializedAdmin = self.libraries.admin.initializeApp();
486
+ } else {
487
+ const serviceAccount = require(self.project.serviceAccountPath);
488
+ const loadedProjectId = serviceAccount.project_id;
489
+ const expectedProjectId = self.project.projectId;
490
+
491
+ // A cert for the wrong project authenticates every Firestore call with the wrong
492
+ // identity — gRPC UNAUTHENTICATED at request time, far from the cause. Refuse to boot.
493
+ // Compare project id to project id, EXACTLY: a brand id is not a project id (brand
494
+ // `omega-playground` runs on project `omegajs-playground`), so matching against the
495
+ // brand — by substring or otherwise — both false-negatives and false-positives.
496
+ // When the expected project is unknown (no FIREBASE_CONFIG), there is nothing to
497
+ // verify against, so boot proceeds rather than guessing.
498
+ if (expectedProjectId && loadedProjectId !== expectedProjectId) {
499
+ throw new Error(`Service account project mismatch: ${loadedProjectId} is not ${expectedProjectId} — fix ${self.project.serviceAccountPath}`);
500
+ }
501
+
502
+ self.libraries.initializedAdmin = self.libraries.admin.initializeApp({
503
+ credential: self.libraries.admin.credential.cert(serviceAccount),
504
+ databaseURL: self.project.databaseURL || `https://${self.project.projectId}.firebaseio.com`,
505
+ }, options.uniqueAppName);
506
+ }
507
+ }
508
+
509
+ // Setup main functions
510
+ if (options.projectType === 'firebase' && options.setupFunctions) {
511
+ self.setupFunctions(exporter, options);
512
+ }
513
+
514
+ // Setup custom server
515
+ if (options.projectType === 'custom' && options.setupServer) {
516
+ self.setupCustomServer(exporter, options);
517
+ }
518
+
519
+ // Setup LocalDatabase
520
+ if (options.initializeLocalStorage) {
521
+ self.storage();
522
+ }
523
+
524
+ // Fetch stats
525
+ if (self.isDevelopment() && options.fetchStats) {
526
+ setTimeout(function () {
527
+ self.ctx.log('Fetching meta/stats...');
528
+ self.libraries.admin
529
+ .firestore().doc('meta/stats')
530
+ .get()
531
+ .then(doc => {
532
+ self.ctx.log('meta/stats', doc.data());
533
+ })
534
+ }, 100);
535
+ }
536
+
537
+ // Send analytics
538
+ self.Analytics({
539
+ ctx: self.ctx,
540
+ uuid: self.SERVER_UUID,
541
+ })
542
+ .event('admin/initialized', {});
543
+
544
+ // Return
545
+ return self;
546
+ };
547
+
548
+ // HELPERS
549
+ Manager.prototype._preProcess = function (mod) {
550
+ const self = this;
551
+ const name = mod.ctx.meta.name;
552
+ return new Promise(async function(resolve, reject) {
553
+ if (self.handlers && self.handlers[name]) {
554
+ let result;
555
+ try {
556
+ result = self.handlers[name](mod)
557
+ } catch (e) {
558
+ mod.ctx.error(e);
559
+ return reject(e);
560
+ }
561
+ if (Promise.resolve(result) == result) {
562
+ result
563
+ .then(r => {
564
+ return resolve(r);
565
+ })
566
+ .catch(e => {
567
+ mod.ctx.error(e);
568
+ return reject(e);
569
+ })
570
+ } else {
571
+ return resolve(result);
572
+ }
573
+ } else {
574
+ return resolve(null);
575
+ }
576
+ });
577
+ };
578
+
579
+ Manager.prototype._handleMcp = function (req, res, routePath) {
580
+ const self = this;
581
+ const cors = self.libraries.cors;
582
+
583
+ return cors(req, res, async () => {
584
+ const { handleMcpRoute } = require('../mcp/handler.js');
585
+ await handleMcpRoute(req, res, {
586
+ Manager: self,
587
+ routePath: routePath,
588
+ });
589
+ });
590
+ };
591
+
592
+ Manager.prototype._processMiddleware = function (req, res, routePath) {
593
+ const self = this;
594
+
595
+ const bemRoutesDir = path.resolve(__dirname, './routes');
596
+ const bemSchemasDir = path.resolve(__dirname, './schemas');
597
+ const consumerRoutesDir = path.normalize(`${self.cwd}${self.options.routes || '/routes'}`);
598
+ const consumerSchemasDir = path.normalize(`${self.cwd}${self.options.schemas || '/schemas'}`);
599
+
600
+ // Check if the route exists in the consumer's routes directory first
601
+ const consumerRoutePath = path.resolve(consumerRoutesDir, routePath);
602
+ const isConsumerRoute = require('fs').existsSync(consumerRoutePath);
603
+
604
+ const routesDir = isConsumerRoute ? consumerRoutesDir : bemRoutesDir;
605
+ const schemasDir = isConsumerRoute ? consumerSchemasDir : bemSchemasDir;
606
+
607
+ return self.Middleware(req, res).run(routePath, {
608
+ routesDir,
609
+ schemasDir,
610
+ schema: routePath,
611
+ });
612
+ };
613
+
614
+ Manager.prototype.RouteContext = function(ref, options) {
615
+ const self = this;
616
+
617
+ // Set options defaults
618
+ ref = ref || {};
619
+ options = options || {};
620
+
621
+ // Create ctx instance
622
+ return (new self.libraries.RouteContext()).init({
623
+ req: ref.req,
624
+ res: ref.res,
625
+ admin: self.libraries.admin,
626
+ functions: self.libraries.functions,
627
+ Manager: self,
628
+ }, options)
629
+ };
630
+
631
+ Manager.prototype.User = function () {
632
+ const self = this;
633
+ self.libraries.User = self.libraries.User || require('./helpers/user.js');
634
+ return new self.libraries.User(self, ...arguments);
635
+ };
636
+
637
+ Manager.prototype.Analytics = function () {
638
+ const self = this;
639
+ self.libraries.Analytics = self.libraries.Analytics || require('./helpers/analytics.js');
640
+ return new self.libraries.Analytics(self, ...arguments);
641
+ };
642
+
643
+ Manager.prototype.ApiManager = function () {
644
+ const self = this;
645
+ self.libraries.ApiManager = self.libraries.ApiManager || require('./helpers/api-manager.js');
646
+ return new self.libraries.ApiManager(self, ...arguments);
647
+ };
648
+
649
+ Manager.prototype.Roles = function () {
650
+ const self = this;
651
+ self.libraries.Roles = self.libraries.Roles || require('./helpers/roles.js');
652
+ return new self.libraries.Roles(self, ...arguments);
653
+ };
654
+
655
+ Manager.prototype.Usage = function () {
656
+ const self = this;
657
+ self.libraries.Usage = self.libraries.Usage || require('./helpers/usage.js');
658
+ return new self.libraries.Usage(self, ...arguments);
659
+ };
660
+
661
+ Manager.prototype.Middleware = function () {
662
+ const self = this;
663
+ self.libraries.Middleware = self.libraries.Middleware || require('./helpers/middleware.js');
664
+ return new self.libraries.Middleware(self, ...arguments);
665
+ };
666
+
667
+ Manager.prototype.BackendRouter = function (req, res) {
668
+ const self = this;
669
+ self.libraries.BackendRouter = self.libraries.BackendRouter || require('./helpers/backend-router.js');
670
+ return new self.libraries.BackendRouter(self, req, res);
671
+ };
672
+
673
+ Manager.prototype.EventMiddleware = function (payload) {
674
+ const self = this;
675
+ self.libraries.EventMiddleware = self.libraries.EventMiddleware || require('./helpers/event-middleware.js');
676
+ return new self.libraries.EventMiddleware(self, payload);
677
+ };
678
+
679
+ Manager.prototype.Settings = function () {
680
+ const self = this;
681
+ self.libraries.Settings = self.libraries.Settings || require('./helpers/settings.js');
682
+ return new self.libraries.Settings(self, ...arguments);
683
+ };
684
+
685
+ Manager.prototype.Metadata = function () {
686
+ const self = this;
687
+ self.libraries.Metadata = self.libraries.Metadata || require('./helpers/metadata.js');
688
+ return new self.libraries.Metadata(self, ...arguments);
689
+ };
690
+
691
+ Manager.prototype.Email = function (ctx) {
692
+ const self = this;
693
+ self.libraries.Email = self.libraries.Email || require('./libraries/email/index.js');
694
+ return new self.libraries.Email(ctx);
695
+ };
696
+
697
+ Manager.prototype.AI = function (ctx, key) {
698
+ const self = this;
699
+ self.libraries.AI = self.libraries.AI || require('./libraries/ai/index.js');
700
+ return new self.libraries.AI(ctx, key);
701
+ };
702
+
703
+ // Manager.prototype.Utilities = function () {
704
+ // const self = this;
705
+ // self.libraries.Utilities = self.libraries.Utilities || require('./helpers/utilities.js');
706
+ // return new self.libraries.Utilities(self, ...arguments);
707
+ // };
708
+
709
+ Manager.prototype.Utilities = function () {
710
+ const self = this;
711
+
712
+ if (!self._internal.utilities) {
713
+ self.libraries.Utilities = require('./helpers/utilities.js');
714
+ self._internal.utilities = new self.libraries.Utilities(self, ...arguments);
715
+ }
716
+
717
+ return self._internal.utilities;
718
+ };
719
+
720
+ Manager.prototype.storage = function (options) {
721
+ const self = this;
722
+ options = options || {};
723
+ options.name = options.name || 'main';
724
+
725
+ if (!self._internal.storage[options.name]) {
726
+ options.temporary = typeof options.temporary === 'undefined' ? false : options.temporary;
727
+ options.clear = typeof options.clear === 'undefined' ? true : options.clear;
728
+ options.log = typeof options.log === 'undefined' ? false : options.log;
729
+
730
+ // Set path
731
+ const subfolder = `storage/${self.options.uniqueAppName || 'primary'}/${options.name}`;
732
+
733
+ // Setup lowdb
734
+ const { LowSync } = require('lowdb');
735
+ const { JSONFileSync } = require('lowdb/node');
736
+ const location = options.temporary
737
+ ? `${require('os').tmpdir()}/${subfolder}.json`
738
+ : `./.data/${subfolder}.json`;
739
+
740
+ // Log
741
+ if (options.log) {
742
+ self.ctx.log('storage(): Location', location);
743
+ }
744
+
745
+ // Clear temporary storage
746
+ if (
747
+ options.temporary
748
+ && self.isDevelopment()
749
+ && options.clear
750
+ ) {
751
+ self.ctx.log('Removed temporary file @', location);
752
+ jetpack.remove(location);
753
+ }
754
+
755
+ // Setup options
756
+ options.clearInvalid = typeof options.clearInvalid === 'undefined'
757
+ ? true
758
+ : options.clearInvalid;
759
+
760
+ function _setup() {
761
+ if (!jetpack.exists(location)) {
762
+ jetpack.write(location, {});
763
+ }
764
+ const db = new LowSync(new JSONFileSync(location), {});
765
+ db.read();
766
+
767
+ // Wrap lowdb in a v1-compatible API so consumers don't need lodash
768
+ self._internal.storage[options.name] = {
769
+ _db: db,
770
+ _location: location,
771
+ get(path, defaultValue) {
772
+ const result = _get(db.data, path, defaultValue);
773
+ return { value() { return result; } };
774
+ },
775
+ set(path, value) { _set(db.data, path, value); return this; },
776
+ write() { db.write(); return this; },
777
+ getState() { return db.data; },
778
+ setState(data) { db.data = data; return this; },
779
+ };
780
+ }
781
+
782
+ try {
783
+ _setup()
784
+ } catch (e) {
785
+ self.ctx.error(`Could not setup storage: ${location}`, e);
786
+
787
+ try {
788
+ if (options.clearInvalid) {
789
+ self.ctx.log(`Clearing invalid storage: ${location}`);
790
+ jetpack.write(location, {});
791
+ }
792
+ _setup()
793
+ } catch (e) {
794
+ self.ctx.error(`Failed to clear invalid storage: ${location}`, e);
795
+ }
796
+ }
797
+ }
798
+
799
+ return self._internal.storage[options.name]
800
+ };
801
+
802
+ Manager.prototype.getCustomServer = function () {
803
+ const self = this;
804
+
805
+ if (!self._internal.server || !self._internal.app) {
806
+ throw new Error('Server not set up');
807
+ }
808
+
809
+ return {
810
+ server: self._internal.server,
811
+ app: self._internal.app,
812
+ };
813
+ };
814
+
815
+ Manager.prototype.install = function (controller, options) {
816
+ const self = this;
817
+
818
+ // Set options defaults
819
+ options = options || {};
820
+ options.prefix = typeof options.prefix === 'undefined' ? null : options.prefix;
821
+ options.dir = typeof options.dir === 'undefined' ? '' : options.dir;
822
+ options.log = typeof options.log === 'undefined' ? false : options.log;
823
+
824
+ // Fix dir
825
+ options.dir = path.resolve(self.cwd, options.dir);
826
+
827
+ // If dir is a single file, install it. if its a directory, install all
828
+ const isDirectory = jetpack.exists(options.dir) === 'dir';
829
+
830
+ if (options.log) {
831
+ self.ctx.log(`Installing from ${options.dir}, prefix=${options.prefix}, isDirectory=${isDirectory}...`);
832
+ }
833
+
834
+ // function _install(prefix, file) {
835
+ // if (!file.includes('.js')) {return}
836
+ // const name = file.replace('.js', '');
837
+ // const _prefix = prefix ? `${prefix}_${name}` : name;
838
+
839
+ // const fullPath = path.resolve(options.dir, file);
840
+
841
+ // if (options.log) {
842
+ // self.ctx.log(`Installing ${_prefix} from ${fullPath}...`);
843
+ // }
844
+
845
+ // controller[`${_prefix}`] = require(fullPath);
846
+ // }
847
+
848
+ function _install(prefix, file) {
849
+ if (!file.includes('.js')) return;
850
+
851
+ const name = file.replace('.js', '');
852
+ const _prefix = prefix ? `${prefix}_${name}` : name;
853
+ const fullPath = path.resolve(options.dir, file);
854
+
855
+ if (options.log) {
856
+ self.ctx.log(`Installing ${_prefix} from ${fullPath}...`);
857
+ }
858
+
859
+ const mod = require(fullPath);
860
+
861
+ // If module exports a function, bind it to controller
862
+ if (typeof mod === 'function') {
863
+ controller[_prefix] = mod.bind(controller);
864
+ } else {
865
+ controller[_prefix] = mod;
866
+ }
867
+ }
868
+
869
+ if (isDirectory) {
870
+ jetpack.list(options.dir)
871
+ .forEach(file => _install(options.prefix, file))
872
+ } else {
873
+ _install(options.prefix, options.dir);
874
+ }
875
+ };
876
+
877
+ // Require
878
+ Manager.prototype.require = function (name) {
879
+ return require(name);
880
+ };
881
+ Manager.require = function (name) {
882
+ return require(name);
883
+ };
884
+
885
+ Manager.prototype.debug = function () {
886
+ return {
887
+ throwException: function () {
888
+ throw new Error('TEST_ERROR');
889
+ },
890
+ throwRejection: function () {
891
+ Promise.reject(new Error('TEST_ERROR'));
892
+ }
893
+ }
894
+ }
895
+
896
+ // Setup functions
897
+ Manager.prototype.setupFunctions = function (exporter, options) {
898
+ const self = this;
899
+ const resourceZone = options.resourceZone;
900
+
901
+ // Helper to create a function builder with region + runtime options
902
+ function fn(runtimeOptions) {
903
+ return self.libraries.functions
904
+ .runWith(runtimeOptions)
905
+ .region(resourceZone);
906
+ }
907
+
908
+ // Log
909
+ if (options.log) {
910
+ self.ctx.log('Setting up Firebase functions...');
911
+ }
912
+
913
+ // Setup functions
914
+ exporter.omega_api =
915
+ fn({memory: '256MB', timeoutSeconds: 60 * 5})
916
+ .https.onRequest(async (req, res) => {
917
+ const route = self.BackendRouter(req, res).resolve();
918
+
919
+ // MCP endpoint — bypass middleware, handle protocol directly
920
+ const mcpRoutePath = resolveMcpRoutePath(route.routePath);
921
+ if (mcpRoutePath) {
922
+ return self._handleMcp(req, res, mcpRoutePath);
923
+ }
924
+
925
+ // RESTful middleware system
926
+ return self._processMiddleware(req, res, route.routePath);
927
+ });
928
+
929
+ // Setup legacy functions
930
+ if (options.setupFunctionsLegacy) {
931
+ exporter.omega_signUpHandler =
932
+ fn({memory: '256MB', timeoutSeconds: 60})
933
+ .https.onRequest(async (req, res) => {
934
+ const Module = require(`${_legacy}/actions/sign-up-handler.js`);
935
+ Module.init(self, { req: req, res: res, });
936
+
937
+ return self._preProcess(Module)
938
+ .then(r => Module.main())
939
+ .catch(e => {
940
+ self.ctx.error(e);
941
+ return res.status(500).send(e.message);
942
+ });
943
+ });
944
+
945
+ // Admin
946
+ exporter.omega_createPost =
947
+ fn({memory: '256MB', timeoutSeconds: 60})
948
+ .https.onRequest(async (req, res) => {
949
+ const Module = require(`${_legacy}/admin/create-post.js`);
950
+ Module.init(self, { req: req, res: res, });
951
+
952
+ return self._preProcess(Module)
953
+ .then(r => Module.main())
954
+ .catch(e => {
955
+ self.ctx.error(e);
956
+ return res.status(500).send(e.message);
957
+ });
958
+ });
959
+
960
+ exporter.omega_firestoreWrite =
961
+ fn({memory: '256MB', timeoutSeconds: 60})
962
+ .https.onRequest(async (req, res) => {
963
+ const Module = require(`${_legacy}/admin/firestore-write.js`);
964
+ Module.init(self, { req: req, res: res, });
965
+
966
+ return self._preProcess(Module)
967
+ .then(r => Module.main())
968
+ .catch(e => {
969
+ self.ctx.error(e);
970
+ return res.status(500).send(e.message);
971
+ });
972
+ });
973
+
974
+ exporter.omega_getStats =
975
+ fn({memory: '256MB', timeoutSeconds: 420})
976
+ .https.onRequest(async (req, res) => {
977
+ const Module = require(`${_legacy}/admin/get-stats.js`);
978
+ Module.init(self, { req: req, res: res, });
979
+
980
+ return self._preProcess(Module)
981
+ .then(r => Module.main())
982
+ .catch(e => {
983
+ self.ctx.error(e);
984
+ return res.status(500).send(e.message);
985
+ });
986
+ });
987
+
988
+ exporter.omega_sendNotification =
989
+ fn({memory: '1GB', timeoutSeconds: 420})
990
+ .https.onRequest(async (req, res) => {
991
+ const Module = require(`${_legacy}/admin/send-notification.js`);
992
+ Module.init(self, { req: req, res: res, });
993
+
994
+ return self._preProcess(Module)
995
+ .then(r => Module.main())
996
+ .catch(e => {
997
+ self.ctx.error(e);
998
+ return res.status(500).send(e.message);
999
+ });
1000
+ });
1001
+
1002
+ exporter.omega_query =
1003
+ fn({memory: '256MB', timeoutSeconds: 60})
1004
+ .https.onRequest(async (req, res) => {
1005
+ const Module = require(`${_legacy}/admin/query.js`);
1006
+ Module.init(self, { req: req, res: res, });
1007
+
1008
+ return self._preProcess(Module)
1009
+ .then(r => Module.main())
1010
+ .catch(e => {
1011
+ self.ctx.error(e);
1012
+ return res.status(500).send(e.message);
1013
+ });
1014
+ });
1015
+
1016
+ exporter.omega_createPostHandler =
1017
+ fn({memory: '256MB', timeoutSeconds: 60})
1018
+ .https.onRequest(async (req, res) => {
1019
+ const Module = require(`${_legacy}/actions/create-post-handler.js`);
1020
+ Module.init(self, { req: req, res: res, });
1021
+
1022
+ return self._preProcess(Module)
1023
+ .then(r => Module.main())
1024
+ .catch(e => {
1025
+ self.ctx.error(e);
1026
+ return res.status(500).send(e.message);
1027
+ });
1028
+ });
1029
+
1030
+ exporter.omega_generateUuid =
1031
+ fn({memory: '256MB', timeoutSeconds: 60})
1032
+ .https.onRequest(async (req, res) => {
1033
+ const Module = require(`${_legacy}/actions/generate-uuid.js`);
1034
+ Module.init(self, { req: req, res: res, });
1035
+
1036
+ return self._preProcess(Module)
1037
+ .then(r => Module.main())
1038
+ .catch(e => {
1039
+ self.ctx.error(e);
1040
+ return res.status(500).send(e.message);
1041
+ });
1042
+ });
1043
+
1044
+ // Test
1045
+ exporter.omega_test_authenticate =
1046
+ fn({memory: '256MB', timeoutSeconds: 60})
1047
+ .https.onRequest(async (req, res) => {
1048
+ const Module = require(`${_legacy}/test/authenticate.js`);
1049
+ Module.init(self, { req: req, res: res, });
1050
+
1051
+ return self._preProcess(Module)
1052
+ .then(r => Module.main())
1053
+ .catch(e => {
1054
+ self.ctx.error(e);
1055
+ return res.status(500).send(e.message);
1056
+ });
1057
+ });
1058
+
1059
+ exporter.omega_test_webhook =
1060
+ fn({memory: '256MB', timeoutSeconds: 60})
1061
+ .https.onRequest(async (req, res) => {
1062
+ const Module = require(`${_legacy}/test/webhook.js`);
1063
+ Module.init(self, { req: req, res: res, });
1064
+
1065
+ return self._preProcess(Module)
1066
+ .then(r => Module.main())
1067
+ .catch(e => {
1068
+ self.ctx.error(e);
1069
+ return res.status(500).send(e.message);
1070
+ });
1071
+ });
1072
+ }
1073
+
1074
+ // Setup identity functions
1075
+ if (options.setupFunctionsIdentity) {
1076
+ exporter.omega_authBeforeCreate =
1077
+ fn({memory: '256MB', timeoutSeconds: 60})
1078
+ .auth.user()
1079
+ .beforeCreate((user, context) => self.EventMiddleware({ user, context }).run(`${events}/auth/before-create.js`));
1080
+
1081
+ exporter.omega_authBeforeSignIn =
1082
+ fn({memory: '256MB', timeoutSeconds: 60})
1083
+ .auth.user()
1084
+ .beforeSignIn((user, context) => self.EventMiddleware({ user, context }).run(`${events}/auth/before-signin.js`));
1085
+ }
1086
+
1087
+ // Setup events
1088
+ exporter.omega_authOnCreate =
1089
+ fn({memory: '256MB', timeoutSeconds: 60})
1090
+ .auth.user()
1091
+ .onCreate((user, context) => self.EventMiddleware({ user, context }).run(`${events}/auth/on-create.js`));
1092
+
1093
+ exporter.omega_authOnDelete =
1094
+ fn({memory: '256MB', timeoutSeconds: 60})
1095
+ .auth.user()
1096
+ .onDelete((user, context) => self.EventMiddleware({ user, context }).run(`${events}/auth/on-delete.js`));
1097
+
1098
+ exporter.omega_notificationsOnWrite =
1099
+ fn({memory: '256MB', timeoutSeconds: 60})
1100
+ .firestore.document('notifications/{token}')
1101
+ .onWrite((change, context) => self.EventMiddleware({ change, context }).run(`${events}/firestore/notifications/on-write.js`));
1102
+
1103
+ exporter.omega_paymentsWebhookOnWrite =
1104
+ fn({memory: '256MB', timeoutSeconds: 60})
1105
+ .firestore.document('payments-webhooks/{eventId}')
1106
+ .onWrite((change, context) => self.EventMiddleware({ change, context }).run(`${events}/firestore/payments-webhooks/on-write.js`));
1107
+
1108
+ exporter.omega_paymentsDisputeOnWrite =
1109
+ fn({memory: '256MB', timeoutSeconds: 60})
1110
+ .firestore.document('payments-disputes/{alertId}')
1111
+ .onWrite((change, context) => self.EventMiddleware({ change, context }).run(`${events}/firestore/payments-disputes/on-write.js`));
1112
+
1113
+ // Setup cron jobs
1114
+ exporter.omega_cronDaily =
1115
+ fn({memory: '256MB', timeoutSeconds: 60 * 5})
1116
+ .pubsub.schedule('0 0 * * *')
1117
+ .onRun((context) => self.EventMiddleware({ context }).run(`${cron}/daily.js`));
1118
+
1119
+ // Frequent cron runs the inline newsletter generator (AI structure + section
1120
+ // images + article + uploads) — needs the v1 max timeout. If a run times out
1121
+ // or OOMs, the campaign lease reclaim in marketing-campaigns.js retries it
1122
+ // safely.
1123
+ exporter.omega_cronFrequent =
1124
+ fn({memory: '256MB', timeoutSeconds: 540})
1125
+ .pubsub.schedule('*/10 * * * *')
1126
+ .onRun((context) => self.EventMiddleware({ context }).run(`${cron}/frequent.js`));
1127
+ };
1128
+
1129
+ // Setup Custom Server
1130
+ Manager.prototype.setupCustomServer = function (_library, options) {
1131
+ const self = this;
1132
+
1133
+ // Require
1134
+ const glob = require('glob').globSync;
1135
+
1136
+ // Log
1137
+ if (options.log) {
1138
+ self.ctx.log('Setting up custom server...');
1139
+ }
1140
+
1141
+ // Setup express
1142
+ const app = require('express')({
1143
+ logger: true,
1144
+ });
1145
+
1146
+ // Setup body parser with configurable limits
1147
+ app.use(require('body-parser').json(options.express.bodyParser.json));
1148
+ app.use(require('body-parser').urlencoded(options.express.bodyParser.urlencoded));
1149
+
1150
+ // Handle errors with custom error handler
1151
+ app.use((err, req, res, next) => {
1152
+ // Create a new ctx because our custom Middleware has not been run yet
1153
+ const ctx = self.RouteContext({ req: req, res: res, }, {});
1154
+
1155
+ // Handle PayloadTooLargeError from body-parser
1156
+ if (err.type === 'entity.too.large') {
1157
+ return ctx.respond('Request payload too large.', { code: 413 });
1158
+ }
1159
+
1160
+ // Catch-all for other body-parser and middleware errors
1161
+ if (err) {
1162
+ // Log
1163
+ // @TODO: REMOVE THIS LOG ONCE WE'RE CONFIDENT IT'S WORKING AS INTENDED
1164
+ console.log('@TODO: Custom Error Handler:', err);
1165
+
1166
+ // Return
1167
+ return ctx.respond(err.message || 'Bad request', { code: err.status || err.code || err.statusCode || 400 });
1168
+ }
1169
+
1170
+ // If no error, continue
1171
+ next(err);
1172
+ });
1173
+
1174
+ // Designate paths
1175
+ const managerRoutesPath = path.normalize(`${__dirname}/routes`);
1176
+ const managerSchemasPath = path.normalize(`${__dirname}/schemas`);
1177
+ const customRoutesPath = path.normalize(`${self.cwd}${options.routes}`);
1178
+ const customSchemasPath = path.normalize(`${self.cwd}${options.schemas}`);
1179
+
1180
+ // Create routes
1181
+ const routes = [];
1182
+
1183
+ // Push function
1184
+ function _push(dir, isManager) {
1185
+ // Get all files (index.js and method-specific files like get.js, post.js)
1186
+ glob('**/*.js', { cwd: dir })
1187
+ .forEach((file) => {
1188
+ const fileName = path.basename(file, '.js');
1189
+ const dirName = path.dirname(file);
1190
+
1191
+ // Determine method and route name
1192
+ let method = 'all'; // default to all methods
1193
+ let routeName;
1194
+
1195
+ if (fileName === 'index') {
1196
+ // Traditional index.js file: routes/restart/index.js -> restart
1197
+ // Root index.js: routes/index.js -> '' (empty string for root path)
1198
+ routeName = dirName === '.' ? '' : dirName;
1199
+ } else if (['get', 'post', 'put', 'delete', 'patch', 'options', 'head'].includes(fileName.toLowerCase())) {
1200
+ // Method-specific file: routes/restart/get.js -> restart (GET only)
1201
+ method = fileName.toLowerCase();
1202
+ routeName = dirName === '.' ? '' : dirName;
1203
+ } else {
1204
+ // Unknown pattern, skip
1205
+ return;
1206
+ }
1207
+
1208
+ // Build the item
1209
+ const item = {
1210
+ name: routeName,
1211
+ method: method,
1212
+ namespace: file,
1213
+ path: path.resolve(dir, file),
1214
+ dir: dir,
1215
+ isManager: isManager,
1216
+ }
1217
+
1218
+ // If it exists in routes with same name AND method, replace it
1219
+ const existing = routes.findIndex(r => r.name === item.name && r.method === item.method);
1220
+ if (existing > -1) {
1221
+ routes[existing] = item;
1222
+ return;
1223
+ }
1224
+
1225
+ // Otherwise, push it
1226
+ routes.push(item);
1227
+ });
1228
+ }
1229
+
1230
+ // Push routes
1231
+ // _push(`${__dirname}/routes`)
1232
+ _push(managerRoutesPath, true)
1233
+ _push(customRoutesPath, false)
1234
+
1235
+ // Log routes
1236
+ // if (options.log) {
1237
+ // self.ctx.log('Routes:', routes);
1238
+ // }
1239
+
1240
+ // Install process
1241
+ routes.forEach((file) => {
1242
+ // self.ctx.log('---file', file);
1243
+ // Require the file
1244
+ const cors = self.libraries.cors;
1245
+
1246
+ // Log
1247
+ // if (options.log) {
1248
+ self.ctx.log(`Initializing route: ${file.method.toUpperCase()} /${file.name} @ ${file.path}`);
1249
+ // }
1250
+
1251
+ // Register the route with the appropriate HTTP method
1252
+ app[file.method](`/${file.name}`, async (req, res) => {
1253
+ return cors(req, res, async () => {
1254
+ // For root route (empty name), skip schema validation
1255
+ const middlewareOptions = {
1256
+ routesDir: file.isManager ? managerRoutesPath : customRoutesPath,
1257
+ schemasDir: file.isManager ? managerSchemasPath : customSchemasPath,
1258
+ };
1259
+
1260
+ // Only set schema if route name is not empty
1261
+ if (file.name) {
1262
+ middlewareOptions.schema = file.name;
1263
+ } else {
1264
+ middlewareOptions.setupSettings = false;
1265
+ }
1266
+
1267
+ self.Middleware(req, res).run(file.name, middlewareOptions)
1268
+ });
1269
+ })
1270
+ });
1271
+
1272
+ // Run the server!
1273
+ const server = app.listen({ port: process.env.PORT || 3000, host: '0.0.0.0' }, (error) => {
1274
+ if (error) {
1275
+ self.ctx.error(error);
1276
+ process.exit(1);
1277
+ }
1278
+
1279
+ const address = server.address();
1280
+
1281
+ // Log
1282
+ if (options.log) {
1283
+ self.ctx.log(`Server listening on ${address.address}:${address.port}`);
1284
+ }
1285
+
1286
+ // Set server and app to internal
1287
+ self._internal.server = server;
1288
+ self._internal.app = app;
1289
+
1290
+ // Emit event
1291
+ self.emit('online', new Event('online'), server, app);
1292
+ });
1293
+ }
1294
+
1295
+ function resolveProjectPackage(dir) {
1296
+ try {
1297
+ return require(path.resolve(dir, 'functions', 'package.json'));
1298
+ } catch (e) {}
1299
+
1300
+ try {
1301
+ return require(path.resolve(dir, 'package.json'));
1302
+ } catch (e) {}
1303
+ }
1304
+
1305
+ /**
1306
+ * Check if a routePath is an MCP-related route and normalize it.
1307
+ * Handles /omega/mcp/* paths and /.well-known/oauth-* discovery.
1308
+ *
1309
+ * @param {string} routePath - Resolved route path from BackendRouter
1310
+ * @returns {string|null} - Normalized MCP route path, or null if not MCP
1311
+ */
1312
+ function resolveMcpRoutePath(routePath) {
1313
+ // Direct MCP paths (via /mcp/* or /omega/mcp/*)
1314
+ if (routePath === 'mcp' || routePath.startsWith('mcp/')) {
1315
+ return routePath;
1316
+ }
1317
+
1318
+ // OAuth discovery (via /.well-known/oauth-*)
1319
+ if (routePath === '.well-known/oauth-protected-resource'
1320
+ || routePath === '.well-known/oauth-authorization-server') {
1321
+ return routePath;
1322
+ }
1323
+
1324
+ // Root-level OAuth paths — Claude Chat sends these directly
1325
+ // regardless of what the discovery endpoints return
1326
+ if (routePath === 'authorize') {
1327
+ return 'mcp/authorize';
1328
+ }
1329
+ if (routePath === 'token') {
1330
+ return 'mcp/token';
1331
+ }
1332
+ if (routePath === 'register') {
1333
+ return 'mcp/register';
1334
+ }
1335
+
1336
+ return null;
1337
+ }
1338
+
1339
+ /**
1340
+ * Install the test-mode-file watcher. Called once during Manager.init() when
1341
+ * running in the test environment (emulator). Reads the shared state file
1342
+ * (`<projectRoot>/.temp/test-mode.json`) at startup to sync any env vars
1343
+ * set by an earlier test command, then watches the file for live changes.
1344
+ *
1345
+ * Idempotent — guarded by a module-level flag so reload-during-nodemon
1346
+ * doesn't stack listeners.
1347
+ *
1348
+ * @param {Manager} manager
1349
+ */
1350
+ let _testModeWatcherInstalled = false;
1351
+ function setupTestModeWatcher(manager) {
1352
+ if (_testModeWatcherInstalled) {
1353
+ return;
1354
+ }
1355
+ _testModeWatcherInstalled = true;
1356
+
1357
+ const fs = require('fs');
1358
+ const jetpack = require('fs-jetpack');
1359
+ const { TEST_MODE_FILENAME, TEMP_DIR_NAME, getTestModeFilePath, readTestMode, applyEnvFromFile } = require('../test/utils/test-mode-file.js');
1360
+
1361
+ // Resolve the consumer's project root. self.cwd is the consumer's
1362
+ // functions/ directory; the test-mode file lives one level up at
1363
+ // <projectRoot>/.temp/test-mode.json.
1364
+ const projectDir = path.dirname(manager.cwd);
1365
+ const filePath = getTestModeFilePath(projectDir);
1366
+ const tempDir = path.join(projectDir, TEMP_DIR_NAME);
1367
+
1368
+ // Initial sync — apply any state the test/emulator command wrote before
1369
+ // this process booted. A sync/flip is an EVENT and always says so; the
1370
+ // resolved mode is per-worker boot noise under the emulator (see
1371
+ // isUnderEmulator) and only announces itself outside one.
1372
+ const initial = readTestMode(projectDir);
1373
+ const changed = applyEnvFromFile(initial);
1374
+ for (const c of changed) {
1375
+ manager.ctx.log(`test-mode sync ${c.key}: ${c.was || '(unset)'} → ${c.now || '(unset)'}`);
1376
+ }
1377
+ if (!isUnderEmulator()) {
1378
+ manager.ctx.log(`test-mode resolved TEST_EXTENDED_MODE=${!!process.env.TEST_EXTENDED_MODE} (file ${initial ? 'present' : 'absent'})`);
1379
+ }
1380
+
1381
+ // Ensure .temp/ exists so we can watch the directory (fs.watch on a missing
1382
+ // path throws synchronously). Watching the directory rather than the file
1383
+ // means deletes/recreations of test-mode.json don't break the watcher, and
1384
+ // we don't depend on whatever writer happened to run first.
1385
+ jetpack.dir(tempDir);
1386
+
1387
+ try {
1388
+ fs.watch(tempDir, { persistent: false }, (eventType, filename) => {
1389
+ // Only react to our file. fs.watch may emit for any change in the dir.
1390
+ if (filename && filename !== TEST_MODE_FILENAME) {
1391
+ return;
1392
+ }
1393
+ const next = readTestMode(projectDir);
1394
+ const flipped = applyEnvFromFile(next);
1395
+ for (const c of flipped) {
1396
+ manager.ctx.log(`test-mode flip ${c.key}: ${c.was || '(unset)'} → ${c.now || '(unset)'}`);
1397
+ }
1398
+ });
1399
+ } catch (e) {
1400
+ manager.ctx.log(`test-mode watcher failed to install (${e.message}), live sync disabled`);
1401
+ }
1402
+ }
1403
+
1404
+ module.exports = Manager;