@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,299 @@
1
+ /**
2
+ * Newsletter structure generator — AI authors the copy + section layout.
3
+ *
4
+ * The schema and AI prompt are NOT fixed here. Each template owns what content
5
+ * it needs and how the AI should write it (template.schema, template.buildPrompt).
6
+ * This module merges the template's contract with the universal base contract
7
+ * (subject, preheader, signoff, citations — things the shell always renders),
8
+ * dispatches the AI call, and normalizes the result.
9
+ *
10
+ * Why template-owned schemas:
11
+ * - Different aesthetics demand fundamentally different content. A "Field
12
+ * Report" template wants bylines + data callouts + dispatch-style prose; a
13
+ * "Postcard" template wants a hand-written note + image caption. Forcing
14
+ * them through one universal `{title, body, cta}` shape produces lookalike
15
+ * output regardless of layout.
16
+ * - The template knows what it's going to render — let it ask for that.
17
+ *
18
+ * Trade-off: theme-only iteration (skipping the AI step on re-runs) only works
19
+ * within the same template. Switching templates means a new AI call, because
20
+ * the cached structure won't match the new template's schema. That's correct
21
+ * behavior — different templates produce different content.
22
+ *
23
+ * Provider defaults to OpenAI (structured JSON output is more reliable on GPT
24
+ * via JSON schema). Can be overridden per-brand via
25
+ * `marketing.newsletter.content.provider.structure`.
26
+ */
27
+ const { resolveNewsletterTemplate: resolveTemplate } = require('./templates/index.js');
28
+
29
+ const DEFAULT_MODELS = {
30
+ openai: 'gpt-5.4-mini',
31
+ anthropic: 'claude-opus',
32
+ 'claude-code': 'claude-opus-4-7',
33
+ };
34
+
35
+ /**
36
+ * BASE_SCHEMA — the universal contract that EVERY newsletter must satisfy
37
+ * regardless of template. These are the fields the shell uses unconditionally
38
+ * (subject/preheader for email metadata, signoff for the closing card,
39
+ * citations for the footnote block).
40
+ *
41
+ * Templates extend this with their own `schema` export, which is merged into
42
+ * `properties` and `required` before the AI call.
43
+ */
44
+ const BASE_SCHEMA = {
45
+ type: 'object',
46
+ additionalProperties: false,
47
+ required: ['subject', 'preheader', 'signoff', 'citations', 'tags', 'summary'],
48
+ properties: {
49
+ subject: { type: 'string', maxLength: 80 },
50
+ preheader: { type: 'string', maxLength: 120 },
51
+ signoff: { type: 'string' },
52
+ // Two-to-three-sentence editorial summary of the issue. Used as the body of
53
+ // `summary.md` alongside the newsletter, and as a preview snippet when the
54
+ // issue is shared. Distinct from preheader (which is an inbox-preview hook).
55
+ summary: { type: 'string', maxLength: 600 },
56
+ // Topical tags for the issue. Flow into Beehiiv's `content_tags` field on
57
+ // the post draft (array of strings, lowercase, kebab-case preferred).
58
+ // Empty array is valid.
59
+ tags: {
60
+ type: 'array',
61
+ maxItems: 5,
62
+ items: { type: 'string', maxLength: 40 },
63
+ },
64
+ // Citations for hard data (statistics, numbers, direct quotes) pulled from sources.
65
+ // Rendered as a small footnote section at the bottom of the newsletter — never inline.
66
+ // Empty array is valid (most newsletters won't need citations).
67
+ citations: {
68
+ type: 'array',
69
+ maxItems: 10,
70
+ items: {
71
+ type: 'object',
72
+ additionalProperties: false,
73
+ required: ['note', 'source'],
74
+ properties: {
75
+ note: { type: 'string' }, // The cited fact, e.g. "70% of social media managers report..."
76
+ source: { type: 'string' }, // Free-form attribution, e.g. "Reported in industry coverage, May 2026"
77
+ },
78
+ },
79
+ },
80
+ },
81
+ };
82
+
83
+ /**
84
+ * Merge a template's schema fragment into BASE_SCHEMA. The template's
85
+ * `properties` are merged in, and its `required` is concatenated.
86
+ *
87
+ * Templates that don't export a schema get BASE_SCHEMA only — they'll be
88
+ * limited to subject/preheader/signoff/citations. That's a useful escape
89
+ * hatch for transactional / receipt-style newsletters that don't need
90
+ * editorial sections.
91
+ */
92
+ function mergeSchemas(base, fragment) {
93
+ if (!fragment) {
94
+ return base;
95
+ }
96
+
97
+ return {
98
+ ...base,
99
+ required: [...(base.required || []), ...(fragment.required || [])],
100
+ properties: {
101
+ ...base.properties,
102
+ ...(fragment.properties || {}),
103
+ },
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Default prompt builder — used by templates that don't override
109
+ * buildPrompt. Produces the "classic" newsletter brief (intro + sections
110
+ * with title/body/cta/image_prompt + signoff).
111
+ *
112
+ * Templates that want a different content shape (Field Report, Almanac,
113
+ * Postcard, etc.) export their own buildPrompt.
114
+ */
115
+ function defaultBuildPrompt({ brand, newsletterConfig, sources }) {
116
+ return {
117
+ system: buildClassicSystemPrompt(brand, newsletterConfig),
118
+ user: buildClassicUserPrompt(sources),
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Generate the newsletter structure from a list of sources.
124
+ *
125
+ * The active template controls the schema and the AI prompt. This function
126
+ * is a generic dispatcher: it resolves the template, merges schemas, asks
127
+ * the template to build the prompt, calls the AI, and normalizes the result.
128
+ *
129
+ * @param {object} args
130
+ * @param {Array<object>} args.sources - Newsletter source records (id, subject, ai: { headline, summary, takeaways })
131
+ * @param {object} args.brand - { name, url, id, description? }
132
+ * @param {object} args.newsletterConfig - marketing.newsletter.content from @omega.js/backend config
133
+ * @param {object} args.ai - AI instance from Manager.AI(ctx)
134
+ * @param {object} args.ctx - @omega.js/backend ctx
135
+ * @returns {Promise<object>} Structured newsletter object
136
+ */
137
+ async function generateStructure({ sources, brand, newsletterConfig, ai, ctx }) {
138
+ if (!sources?.length) {
139
+ throw new Error('generateStructure requires at least one source');
140
+ }
141
+
142
+ const templateName = newsletterConfig?.template || 'clean';
143
+ const template = resolveTemplate(templateName);
144
+
145
+ const provider = newsletterConfig?.provider?.structure || 'openai';
146
+ const model = newsletterConfig?.model?.structure || DEFAULT_MODELS[provider];
147
+ const startTime = Date.now();
148
+
149
+ // Build the schema: BASE + template-specific fields
150
+ const schema = mergeSchemas(BASE_SCHEMA, template.schema);
151
+
152
+ // Build the AI prompt: template owns voice/structure brief, base owns attribution rules
153
+ const buildPrompt = template.buildPrompt || defaultBuildPrompt;
154
+ const { system, user } = buildPrompt({ brand, newsletterConfig, sources });
155
+
156
+ ctx.log(`Newsletter structure: template=${templateName} provider=${provider} model=${model} sources=${sources.length}`);
157
+
158
+ const result = await ai.request({
159
+ provider,
160
+ model,
161
+ messages: [
162
+ { role: 'system', content: system },
163
+ { role: 'user', content: user },
164
+ ],
165
+ response: 'json',
166
+ schema,
167
+ maxTokens: 3000,
168
+ temperature: 0.7,
169
+ moderate: false,
170
+ });
171
+
172
+ const structure = result.content;
173
+
174
+ // Validate universals
175
+ if (!structure?.subject) {
176
+ throw new Error('AI returned invalid newsletter structure (missing subject)');
177
+ }
178
+
179
+ // Normalize universals
180
+ structure.subject = structure.subject || '';
181
+ structure.preheader = structure.preheader || '';
182
+ structure.signoff = structure.signoff || `Best,\nThe ${brand?.name || 'Team'} Team`;
183
+ structure.citations = Array.isArray(structure.citations) ? structure.citations : [];
184
+ structure.tags = Array.isArray(structure.tags) ? structure.tags : [];
185
+ structure.summary = typeof structure.summary === 'string' ? structure.summary : '';
186
+
187
+ // Let the template normalize its own fields (e.g. sections defaults).
188
+ // Falls back to a sane default if the template doesn't ship one.
189
+ if (typeof template.normalize === 'function') {
190
+ template.normalize(structure, { brand, newsletterConfig });
191
+ }
192
+
193
+ // Attach metadata (non-enumerable so it doesn't pollute JSON serialization of the structure itself)
194
+ Object.defineProperty(structure, '_meta', {
195
+ enumerable: false,
196
+ value: {
197
+ template: templateName,
198
+ provider,
199
+ model,
200
+ durationMs: Date.now() - startTime,
201
+ sourcesIn: sources.length,
202
+ tokens: result.tokens || null,
203
+ },
204
+ });
205
+
206
+ return structure;
207
+ }
208
+
209
+ // ---------- Default "classic" prompt (clean + editorial use this) ----------
210
+
211
+ function buildClassicSystemPrompt(brand, config) {
212
+ const tone = config?.tone || 'professional';
213
+ const instructions = config?.instructions || '';
214
+ const links = config?.links || [];
215
+ const keywords = config?.keywords || [];
216
+ const taglineLine = brand?.tagline ? `\nTagline: ${brand.tagline}` : '';
217
+ const descriptionLine = brand?.description ? `\nDescription: ${brand.description}` : '';
218
+
219
+ return [
220
+ `You are a newsletter writer for ${brand?.name || 'a tech company'}.${taglineLine}${descriptionLine}`,
221
+ instructions ? `\nBrand instructions:\n${instructions}` : '',
222
+ `\nTone: ${tone}`,
223
+ keywords.length ? `\nKeywords to weave in naturally: ${keywords.join(', ')}` : '',
224
+ links.length ? `\nBrand links to incorporate where relevant: ${links.join(', ')}` : '',
225
+ '',
226
+ 'You will be given a set of "source articles" — these are background research, NOT publications you are writing for or about.',
227
+ 'Treat them as raw information. Synthesize the IDEAS into original content written as if you are the original author.',
228
+ '',
229
+ 'CRITICAL ATTRIBUTION RULES:',
230
+ '- NEVER name the source publication, newsletter, blog, or author in the body of the newsletter.',
231
+ ' (e.g., do NOT write "according to Daily Carnage", "as reported by Morning Brew", "Forbes says…", etc.)',
232
+ '- NEVER use phrases like "a recent article said", "according to sources", "industry coverage", or similar dodges that hint at the source.',
233
+ '- Write the body AS IF the source did not exist — the content should read as original, first-party reporting from the brand.',
234
+ '- If a source mentions a third-party platform, product, or company by name (e.g., LinkedIn, YouTube, Apple), THAT is fine — those are subjects of the news, not the source. Name them freely.',
235
+ '',
236
+ 'CITATIONS:',
237
+ '- If the source contains hard data — specific statistics, percentages, dollar amounts, dates, study results — paraphrase them before including in the body. Never copy exact figures from the source. Round numbers, change units or scale, reframe percentages as ratios or fractions, and vary phrasing. The meaning and magnitude must stay accurate but the expression must be different enough that it cannot be traced back to the source (e.g. "$7.5 billion" becomes "north of $7 billion"; "60%" becomes "close to six in ten"; "47,000 of 500,000" becomes "fewer than 50,000 of a planned half-million").',
238
+ '- Then add a corresponding entry to the `citations` array with:',
239
+ ' - note: the cited fact (e.g. "Crosscheck AI flagged 12,000 impersonation attempts in beta")',
240
+ ' - source: a neutral attribution that does NOT name the source publication (e.g. "Reported by LinkedIn product team, May 2026", "Per company beta data", "Industry research, Q2 2026")',
241
+ '- Citations render as small footnotes at the BOTTOM of the newsletter — never inline.',
242
+ '- If a section has no hard data worth citing, do not invent citations. Empty array is fine.',
243
+ '',
244
+ 'CONTENT REQUIREMENTS:',
245
+ '- Subject (≤60 chars, no emojis, attention-grabbing but not clickbait)',
246
+ '- Preheader (≤100 chars, complements the subject)',
247
+ '- Summary (2-3 sentences, plain text, no markdown) — an editorial recap of the issue, written like a TL;DR. Distinct from preheader (which is an inbox hook). This is what someone reads if they only have 10 seconds.',
248
+ '- Tags (3-5 short topical tags, lowercase, kebab-case, no spaces) — e.g. "linkedin", "creator-economy", "platform-policy". Empty array is fine if nothing fits.',
249
+ '- Intro (1-2 sentences, markdown allowed) — frame the issue as if you are setting up your own reporting',
250
+ '- 3-5 sections — each is ONE topic, rewritten in your voice as original content',
251
+ '- Each section: title (compelling, scannable), body (80-150 words, markdown OK)',
252
+ '- Each section: image_prompt — one-sentence visual description for an illustrator. Be specific about subject/style.',
253
+ '- Do NOT invent URLs or "read more" links. The newsletter is a self-contained read. The ONLY URLs allowed in section bodies are the brand links listed above (if any) — weave them in naturally where relevant, do not force them.',
254
+ `- Signoff: a SHORT human sign-off, formatted as two lines with \\n between them. First line is a closing phrase like "Best,", "Cheers,", "Until next week,", or "Stay sharp,". Second line is the team name like "The ${brand?.name || 'Team'} Team". Example: "Best,\\nThe ${brand?.name || 'Team'} Team". Do NOT write a summary, tagline, motto, or thematic conclusion sentence — this is the literal way you sign off the email, like the end of a letter.`,
255
+ '- citations: array of { note, source } for any hard data referenced. Empty array if none.',
256
+ '',
257
+ 'STYLE:',
258
+ '- Do NOT copy source text verbatim. Paraphrase all facts, figures, and phrasing. Synthesize and rewrite in your voice.',
259
+ '- Do NOT use emojis, hashtags, or "guru" language unless brand instructions say otherwise.',
260
+ '- Respond with valid JSON only — no markdown fences, no preamble.',
261
+ ].filter(Boolean).join('\n');
262
+ }
263
+
264
+ function buildClassicUserPrompt(sources) {
265
+ // Note: we intentionally do NOT pass through the source publication name (raw.from)
266
+ // to the AI prompt. Removing it means the AI literally cannot leak it into the body.
267
+ // The "from" field is metadata about WHERE the research came from, not content to reference.
268
+ const summaries = sources
269
+ .map((s, i) => {
270
+ const raw = s.source || {};
271
+ const headline = s.ai?.headline || raw.subject || s.subject || `Topic ${i + 1}`;
272
+ const summary = s.ai?.summary || '';
273
+ const takeaways = (s.ai?.takeaways || []).join('; ');
274
+ const rawContent = !summary && raw.content
275
+ ? raw.content.slice(0, 1500)
276
+ : '';
277
+
278
+ return [
279
+ `[Research ${i + 1}]`,
280
+ `Topic: ${headline}`,
281
+ summary ? `Summary: ${summary}` : '',
282
+ takeaways ? `Key takeaways: ${takeaways}` : '',
283
+ rawContent ? `Raw content (excerpt):\n${rawContent}` : '',
284
+ ].filter(Boolean).join('\n');
285
+ })
286
+ .join('\n\n');
287
+
288
+ return `Write a newsletter using the following research as background. Do not name or reference these research items — synthesize the ideas into original content.\n\n${summaries}`;
289
+ }
290
+
291
+ module.exports = {
292
+ generateStructure,
293
+ BASE_SCHEMA,
294
+ defaultBuildPrompt,
295
+ mergeSchemas,
296
+ // Re-exported helpers so templates can reuse the classic prompt patterns
297
+ buildClassicSystemPrompt,
298
+ buildClassicUserPrompt,
299
+ };
@@ -0,0 +1,197 @@
1
+ /**
2
+ * SVG illustrator — AI authors per-section SVG illustrations, rasterized to PNG.
3
+ *
4
+ * Each section in a newsletter gets one illustration. Default provider is
5
+ * OpenAI Codex (gpt-5.3-codex) — markup/code-specialized GPT-5 variant tuned
6
+ * for structured output. SVG is just structured markup, so Codex is the right
7
+ * fit. Anthropic is supported as a fallback provider.
8
+ *
9
+ * Output is both the raw SVG string (for debugging) and a rasterized PNG buffer
10
+ * (for embedding). Local file persistence is the caller's responsibility — this
11
+ * module returns buffers only.
12
+ *
13
+ * Provider-specific default models:
14
+ * openai → gpt-5.3-codex (Codex family is markup/code-specialized; SVG is
15
+ * structured markup. ~$0.005-0.015/image.)
16
+ * anthropic → claude-opus (Claude is good at artistic SVG.)
17
+ */
18
+ const { Resvg } = require('@resvg/resvg-js');
19
+ const { emptyTokens, addTokens } = require('../../../ai/tokens.js');
20
+
21
+ const DEFAULT_PROVIDER = 'openai';
22
+
23
+ const DEFAULT_MODELS = {
24
+ openai: 'gpt-5.3-codex',
25
+ anthropic: 'claude-opus',
26
+ 'claude-code': 'claude-opus-4-7',
27
+ };
28
+
29
+ const PNG_WIDTH = 800; // 2x display width of 400px container
30
+
31
+ /**
32
+ * Generate one illustration for a section.
33
+ *
34
+ * @param {object} args
35
+ * @param {string} args.imagePrompt - Visual description from the structure
36
+ * @param {object} args.brand - { name, color: { primary, secondary, ... } }
37
+ * @param {object} args.newsletterConfig - marketing.newsletter.content
38
+ * @param {object} args.ai - AI instance
39
+ * @param {object} args.ctx - @omega.js/backend ctx
40
+ * @returns {Promise<{svg: string, png: Buffer, fallback: boolean}>}
41
+ */
42
+ async function generateSectionImage({ imagePrompt, brand, newsletterConfig, ai, ctx }) {
43
+ const provider = newsletterConfig?.provider?.svg || DEFAULT_PROVIDER;
44
+ const model = newsletterConfig?.model?.svg || DEFAULT_MODELS[provider];
45
+ const startTime = Date.now();
46
+
47
+ const palette = resolvePalette(brand, newsletterConfig);
48
+ const systemPrompt = buildSvgSystemPrompt(palette);
49
+ const userPrompt = imagePrompt || 'An abstract geometric illustration representing the topic.';
50
+
51
+ let svg = '';
52
+ let fallback = false;
53
+ let attempts = 0;
54
+
55
+ // Every attempt reports its OWN usage, so a discarded first attempt still
56
+ // cost money — accumulate, never overwrite, or the newsletter totals under-report
57
+ let tokens = null;
58
+
59
+ for (let attempt = 0; attempt < 2; attempt++) {
60
+ attempts++;
61
+ try {
62
+ const result = await ai.request({
63
+ provider,
64
+ model,
65
+ messages: [
66
+ { role: 'system', content: systemPrompt },
67
+ { role: 'user', content: userPrompt },
68
+ ],
69
+ response: 'text',
70
+ maxTokens: 2000,
71
+ temperature: attempt === 0 ? 0.8 : 0.4,
72
+ moderate: false,
73
+ });
74
+
75
+ tokens = addTokens(tokens || emptyTokens(), result.tokens);
76
+ svg = extractSvg(result.content);
77
+
78
+ if (svg) {
79
+ break;
80
+ }
81
+
82
+ ctx.log(`SVG generation attempt ${attempt + 1} returned no valid <svg>`);
83
+ } catch (e) {
84
+ ctx.error(`SVG generation attempt ${attempt + 1} failed: ${e.message}`);
85
+ }
86
+ }
87
+
88
+ let png;
89
+
90
+ if (svg) {
91
+ try {
92
+ png = rasterize(svg);
93
+ } catch (e) {
94
+ ctx.error(`SVG rasterization failed, using fallback: ${e.message}`);
95
+ svg = buildPlaceholderSvg(palette);
96
+ png = rasterize(svg);
97
+ fallback = true;
98
+ }
99
+ } else {
100
+ svg = buildPlaceholderSvg(palette);
101
+ png = rasterize(svg);
102
+ fallback = true;
103
+ }
104
+
105
+ return {
106
+ svg,
107
+ png,
108
+ fallback,
109
+ meta: {
110
+ provider,
111
+ model,
112
+ durationMs: Date.now() - startTime,
113
+ attempts,
114
+ fallback,
115
+ tokens: tokens,
116
+ },
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Resolve brand palette from config theme + brand defaults.
122
+ * Returns { primary, secondary, accent, bg, fg }
123
+ */
124
+ function resolvePalette(brand, newsletterConfig) {
125
+ const theme = newsletterConfig?.theme || {};
126
+
127
+ return {
128
+ primary: theme.primaryColor || brand?.color?.primary || '#5B5BFF',
129
+ secondary: theme.secondaryColor || brand?.color?.secondary || '#1E1E2A',
130
+ accent: theme.accentColor || brand?.color?.accent || '#F6F7FB',
131
+ bg: '#FFFFFF',
132
+ fg: '#1E1E2A',
133
+ };
134
+ }
135
+
136
+ function buildSvgSystemPrompt(palette) {
137
+ return [
138
+ 'You are an SVG illustrator. Produce a single self-contained SVG illustration.',
139
+ '',
140
+ 'STRICT REQUIREMENTS:',
141
+ '- viewBox="0 0 800 400"',
142
+ '- No <text>, no <foreignObject>, no <script>, no <image>, no external references',
143
+ '- Use only: <rect>, <circle>, <ellipse>, <path>, <line>, <polyline>, <polygon>, <g>',
144
+ '- Maximum 20 shape elements total',
145
+ '- No filters, no gradients beyond simple <linearGradient>',
146
+ '- Output ONLY the SVG element. No markdown fences, no preamble, no explanation.',
147
+ '',
148
+ 'PALETTE (use these colors exclusively):',
149
+ `- Primary: ${palette.primary}`,
150
+ `- Secondary: ${palette.secondary}`,
151
+ `- Accent: ${palette.accent}`,
152
+ `- Background: ${palette.bg}`,
153
+ '',
154
+ 'STYLE: Flat, geometric, modern, minimal. Think Stripe, Linear, or Vercel marketing illustrations.',
155
+ 'COMPOSITION: Centered subject, balanced negative space, no busy clutter.',
156
+ ].join('\n');
157
+ }
158
+
159
+ function extractSvg(text) {
160
+ if (!text || typeof text !== 'string') {
161
+ return null;
162
+ }
163
+
164
+ // Strip markdown fences
165
+ const cleaned = text.trim().replace(/^```(?:svg|xml)?\s*/i, '').replace(/\s*```$/i, '');
166
+
167
+ // Find first <svg ... > ... </svg>
168
+ const match = cleaned.match(/<svg[\s\S]*?<\/svg>/i);
169
+
170
+ if (!match) {
171
+ return null;
172
+ }
173
+
174
+ return match[0];
175
+ }
176
+
177
+ function buildPlaceholderSvg(palette) {
178
+ return [
179
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 400">',
180
+ ` <rect width="800" height="400" fill="${palette.accent}"/>`,
181
+ ` <circle cx="400" cy="200" r="120" fill="${palette.primary}" opacity="0.85"/>`,
182
+ ` <circle cx="320" cy="160" r="60" fill="${palette.secondary}" opacity="0.7"/>`,
183
+ ` <rect x="480" y="240" width="120" height="80" fill="${palette.primary}" opacity="0.4"/>`,
184
+ '</svg>',
185
+ ].join('\n');
186
+ }
187
+
188
+ function rasterize(svgString) {
189
+ const resvg = new Resvg(svgString, {
190
+ fitTo: { mode: 'width', value: PNG_WIDTH },
191
+ background: 'rgba(0,0,0,0)',
192
+ });
193
+
194
+ return resvg.render().asPng();
195
+ }
196
+
197
+ module.exports = { generateSectionImage, rasterize };