@omega.js/manager 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 (416) hide show
  1. package/.claude-plugin/marketplace.json +14 -0
  2. package/LICENSE +98 -0
  3. package/README.md +165 -0
  4. package/bin/omega +2 -0
  5. package/bin/omg +2 -0
  6. package/claude-plugin/.claude-plugin/plugin.json +11 -0
  7. package/claude-plugin/.mcp.json +9 -0
  8. package/claude-plugin/README.md +139 -0
  9. package/claude-plugin/hooks/gate/mark.sh +58 -0
  10. package/claude-plugin/hooks/gate/run.sh +97 -0
  11. package/claude-plugin/hooks/guard/run.sh +249 -0
  12. package/claude-plugin/hooks/hooks.json +63 -0
  13. package/claude-plugin/hooks/inject/run.sh +127 -0
  14. package/claude-plugin/hooks/lib/omega-gate.sh +20 -0
  15. package/claude-plugin/hooks/lib/omega-scope.sh +41 -0
  16. package/claude-plugin/hooks/lib/omega-skills.sh +209 -0
  17. package/claude-plugin/hooks/quality/run.sh +132 -0
  18. package/claude-plugin/hooks/shape/run.sh +45 -0
  19. package/claude-plugin/mcp-router-launch.js +29 -0
  20. package/claude-plugin/skills/README.md +48 -0
  21. package/claude-plugin/skills/accessibility/SKILL.md +31 -0
  22. package/claude-plugin/skills/analytics/SKILL.md +30 -0
  23. package/claude-plugin/skills/backend/SKILL.md +25 -0
  24. package/claude-plugin/skills/brandcheck/SKILL.md +29 -0
  25. package/claude-plugin/skills/browser/SKILL.md +64 -0
  26. package/claude-plugin/skills/client/SKILL.md +24 -0
  27. package/claude-plugin/skills/desktop/SKILL.md +25 -0
  28. package/claude-plugin/skills/extension/SKILL.md +25 -0
  29. package/claude-plugin/skills/main/SKILL.md +54 -0
  30. package/claude-plugin/skills/manager/SKILL.md +25 -0
  31. package/claude-plugin/skills/seo/SKILL.md +36 -0
  32. package/claude-plugin/skills/theme/SKILL.md +33 -0
  33. package/claude-plugin/skills/web/SKILL.md +29 -0
  34. package/dist/cli-run.js +34 -0
  35. package/dist/cli.js +29 -0
  36. package/dist/commands/build.js +17 -0
  37. package/dist/commands/clean.js +16 -0
  38. package/dist/commands/company.js +46 -0
  39. package/dist/commands/deploy.js +143 -0
  40. package/dist/commands/dev.js +437 -0
  41. package/dist/commands/devlog.js +25 -0
  42. package/dist/commands/help.js +48 -0
  43. package/dist/commands/manage.js +53 -0
  44. package/dist/commands/migrate.js +76 -0
  45. package/dist/commands/onboard.js +31 -0
  46. package/dist/commands/pipeline.js +319 -0
  47. package/dist/commands/test.js +380 -0
  48. package/dist/commands/update.js +128 -0
  49. package/dist/commands/version.js +8 -0
  50. package/dist/company-init.js +167 -0
  51. package/dist/company.js +283 -0
  52. package/dist/config.js +1359 -0
  53. package/dist/devlog/index.js +226 -0
  54. package/dist/devlog/lib/collect-commits.js +136 -0
  55. package/dist/devlog/lib/generate-post.js +201 -0
  56. package/dist/devlog/lib/ghostii.js +122 -0
  57. package/dist/devlog/lib/project-map.js +98 -0
  58. package/dist/devlog/lib/publish-website.js +88 -0
  59. package/dist/index.js +45 -0
  60. package/dist/lib/agents-md.js +201 -0
  61. package/dist/lib/analytics-secret.js +22 -0
  62. package/dist/lib/argv.js +21 -0
  63. package/dist/lib/auth-admin.js +120 -0
  64. package/dist/lib/automation-client.js +210 -0
  65. package/dist/lib/backend-marketing.js +49 -0
  66. package/dist/lib/brand.js +240 -0
  67. package/dist/lib/bundle-id.js +53 -0
  68. package/dist/lib/claude-settings.js +125 -0
  69. package/dist/lib/company-scaffold.js +213 -0
  70. package/dist/lib/company.js +227 -0
  71. package/dist/lib/config-flow.js +350 -0
  72. package/dist/lib/config-write.js +41 -0
  73. package/dist/lib/custom-target.js +75 -0
  74. package/dist/lib/domain-utils.js +19 -0
  75. package/dist/lib/duration.js +39 -0
  76. package/dist/lib/env-order.js +236 -0
  77. package/dist/lib/env-secret.js +78 -0
  78. package/dist/lib/firestore-rest.js +326 -0
  79. package/dist/lib/framework-bin.js +156 -0
  80. package/dist/lib/gitignore.js +63 -0
  81. package/dist/lib/google-auth.js +495 -0
  82. package/dist/lib/google-token.js +66 -0
  83. package/dist/lib/jwt.js +31 -0
  84. package/dist/lib/legacy-oauth.js +59 -0
  85. package/dist/lib/node-version.js +127 -0
  86. package/dist/lib/owner-plan.js +78 -0
  87. package/dist/lib/package-scripts.js +152 -0
  88. package/dist/lib/preflight.js +470 -0
  89. package/dist/lib/product-create.js +144 -0
  90. package/dist/lib/run-command.js +74 -0
  91. package/dist/lib/run-gates.js +70 -0
  92. package/dist/lib/run-output.js +42 -0
  93. package/dist/lib/run-summary.js +384 -0
  94. package/dist/lib/scaffold.js +427 -0
  95. package/dist/lib/service-input.js +207 -0
  96. package/dist/lib/service-runner.js +466 -0
  97. package/dist/lib/stale.js +24 -0
  98. package/dist/lib/target-selection.js +155 -0
  99. package/dist/lib/verb-fanout.js +128 -0
  100. package/dist/lib/verify-live.js +188 -0
  101. package/dist/manage.js +311 -0
  102. package/dist/omega-bin.js +7 -0
  103. package/dist/onboard.js +532 -0
  104. package/dist/services/account/ensure/users.js +259 -0
  105. package/dist/services/account/index.js +97 -0
  106. package/dist/services/account/lib/backend-client.js +107 -0
  107. package/dist/services/account/lib/password.js +36 -0
  108. package/dist/services/account/lib/resolve-password.js +100 -0
  109. package/dist/services/advertising/ensure/sites.js +101 -0
  110. package/dist/services/advertising/index.js +101 -0
  111. package/dist/services/advertising/lib/adsense-api.js +41 -0
  112. package/dist/services/ai/ensure/keys.js +21 -0
  113. package/dist/services/ai/index.js +36 -0
  114. package/dist/services/analytics/ensure/google-firebase-link.js +230 -0
  115. package/dist/services/analytics/ensure/google-streams.js +256 -0
  116. package/dist/services/analytics/ensure/meta-pixel.js +22 -0
  117. package/dist/services/analytics/ensure/tiktok-pixel.js +22 -0
  118. package/dist/services/analytics/index.js +134 -0
  119. package/dist/services/analytics/lib/analytics-api.js +156 -0
  120. package/dist/services/analytics/lib/meta-api.js +83 -0
  121. package/dist/services/analytics/lib/pixel-account.js +78 -0
  122. package/dist/services/analytics/lib/pixel-provision.js +152 -0
  123. package/dist/services/analytics/lib/pixel-specs.js +57 -0
  124. package/dist/services/analytics/lib/pixel-token.js +88 -0
  125. package/dist/services/analytics/lib/property-flow.js +77 -0
  126. package/dist/services/analytics/lib/tiktok-api.js +157 -0
  127. package/dist/services/analytics/lib/tiktok-auth.js +153 -0
  128. package/dist/services/assets/ensure/logo-gen.js +68 -0
  129. package/dist/services/assets/index.js +109 -0
  130. package/dist/services/assets/lib/assets-config.js +168 -0
  131. package/dist/services/assets/lib/brandmark-api.js +160 -0
  132. package/dist/services/assets/lib/derived.js +113 -0
  133. package/dist/services/assets/lib/font-loader.js +67 -0
  134. package/dist/services/assets/lib/reconcile.js +122 -0
  135. package/dist/services/assets/lib/reset.js +118 -0
  136. package/dist/services/assets/lib/svg-logo-generator.js +154 -0
  137. package/dist/services/assets/lib/svg-to-black.js +32 -0
  138. package/dist/services/assets/write/favicons.js +82 -0
  139. package/dist/services/assets/write/icons.js +64 -0
  140. package/dist/services/assets/write/process.js +96 -0
  141. package/dist/services/assets/write/reconcile.js +30 -0
  142. package/dist/services/assets/write/social-icons.js +108 -0
  143. package/dist/services/assets/write/templates.js +345 -0
  144. package/dist/services/bookmark/ensure/sync.js +255 -0
  145. package/dist/services/bookmark/index.js +17 -0
  146. package/dist/services/campaigns/ensure/contact-person.js +40 -0
  147. package/dist/services/campaigns/ensure/custom-fields.js +84 -0
  148. package/dist/services/campaigns/ensure/domain-auth.js +92 -0
  149. package/dist/services/campaigns/ensure/event-webhook.js +89 -0
  150. package/dist/services/campaigns/ensure/link-branding.js +187 -0
  151. package/dist/services/campaigns/ensure/list.js +50 -0
  152. package/dist/services/campaigns/ensure/segments.js +109 -0
  153. package/dist/services/campaigns/ensure/sender-identity.js +153 -0
  154. package/dist/services/campaigns/ensure/unsubscribe-groups.js +116 -0
  155. package/dist/services/campaigns/index.js +79 -0
  156. package/dist/services/campaigns/lib/dns-sync.js +81 -0
  157. package/dist/services/campaigns/lib/segment-query.js +138 -0
  158. package/dist/services/campaigns/lib/sendgrid-api.js +287 -0
  159. package/dist/services/captcha/ensure/site-key.js +83 -0
  160. package/dist/services/captcha/index.js +78 -0
  161. package/dist/services/captcha/lib/console-url.js +45 -0
  162. package/dist/services/captcha/lib/recaptcha-api.js +36 -0
  163. package/dist/services/certificates/ensure/api-key.js +22 -0
  164. package/dist/services/certificates/ensure/bundle-ids.js +115 -0
  165. package/dist/services/certificates/ensure/certificates.js +187 -0
  166. package/dist/services/certificates/ensure/profiles.js +143 -0
  167. package/dist/services/certificates/index.js +225 -0
  168. package/dist/services/certificates/lib/apple-api.js +183 -0
  169. package/dist/services/certificates/lib/certificate-manager.js +252 -0
  170. package/dist/services/certificates/lib/identifier-manager.js +107 -0
  171. package/dist/services/certificates/lib/keychain.js +135 -0
  172. package/dist/services/certificates/lib/manual-walkthrough.js +165 -0
  173. package/dist/services/certificates/lib/profile-manager.js +115 -0
  174. package/dist/services/chat/data/baseline-knowledge.md +96 -0
  175. package/dist/services/chat/ensure/chat.js +106 -0
  176. package/dist/services/chat/ensure/user.js +45 -0
  177. package/dist/services/chat/index.js +139 -0
  178. package/dist/services/chat/lib/baseline-knowledge.js +137 -0
  179. package/dist/services/cloud/ensure/authentication.js +267 -0
  180. package/dist/services/cloud/ensure/billing.js +120 -0
  181. package/dist/services/cloud/ensure/cloud-messaging.js +105 -0
  182. package/dist/services/cloud/ensure/database.js +60 -0
  183. package/dist/services/cloud/ensure/firestore.js +79 -0
  184. package/dist/services/cloud/ensure/functions.js +49 -0
  185. package/dist/services/cloud/ensure/hosting.js +398 -0
  186. package/dist/services/cloud/ensure/oauth-consent.js +248 -0
  187. package/dist/services/cloud/ensure/project-settings.js +72 -0
  188. package/dist/services/cloud/ensure/sdk-config.js +95 -0
  189. package/dist/services/cloud/ensure/service-account.js +152 -0
  190. package/dist/services/cloud/ensure/services.js +103 -0
  191. package/dist/services/cloud/ensure/storage.js +47 -0
  192. package/dist/services/cloud/index.js +130 -0
  193. package/dist/services/cloud/lib/access-heal.js +130 -0
  194. package/dist/services/cloud/lib/firebase-api.js +662 -0
  195. package/dist/services/cloud/lib/project-flow.js +102 -0
  196. package/dist/services/directory/ensure/entry.js +48 -0
  197. package/dist/services/directory/index.js +64 -0
  198. package/dist/services/directory/lib/blocks.js +104 -0
  199. package/dist/services/disperse/index.js +45 -0
  200. package/dist/services/disperse/write/certs.js +117 -0
  201. package/dist/services/domain/ensure/nameservers.js +179 -0
  202. package/dist/services/domain/index.js +69 -0
  203. package/dist/services/domain/lib/namecheap-api.js +167 -0
  204. package/dist/services/domain/lib/registrars.js +46 -0
  205. package/dist/services/domain/lib/whitelist-walkthrough.js +76 -0
  206. package/dist/services/edge/ensure/cache-rules.js +105 -0
  207. package/dist/services/edge/ensure/dns-records.js +304 -0
  208. package/dist/services/edge/ensure/email-routing.js +292 -0
  209. package/dist/services/edge/ensure/rules-configuration.js +98 -0
  210. package/dist/services/edge/ensure/rules-managed-transforms.js +101 -0
  211. package/dist/services/edge/ensure/rules-redirect.js +107 -0
  212. package/dist/services/edge/ensure/rules-response-headers.js +90 -0
  213. package/dist/services/edge/ensure/rules-security.js +142 -0
  214. package/dist/services/edge/ensure/speed-scheduled-tests.js +98 -0
  215. package/dist/services/edge/ensure/workers.js +219 -0
  216. package/dist/services/edge/ensure/zone-settings.js +108 -0
  217. package/dist/services/edge/ensure/zone.js +183 -0
  218. package/dist/services/edge/index.js +73 -0
  219. package/dist/services/edge/lib/cloudflare-api.js +84 -0
  220. package/dist/services/edge/lib/dns-records-helpers.js +518 -0
  221. package/dist/services/edge/lib/read-cache.js +16 -0
  222. package/dist/services/edge/lib/ruleset-helper.js +108 -0
  223. package/dist/services/edge/workers/omega-api-proxy.js +43 -0
  224. package/dist/services/email/data/baseline-filter.md +4 -0
  225. package/dist/services/email/data/baseline-knowledge.md +86 -0
  226. package/dist/services/email/ensure/agent.js +107 -0
  227. package/dist/services/email/ensure/user.js +45 -0
  228. package/dist/services/email/index.js +138 -0
  229. package/dist/services/email/lib/baseline.js +82 -0
  230. package/dist/services/email/lib/knowledge-file.js +53 -0
  231. package/dist/services/forms/ensure/form.js +46 -0
  232. package/dist/services/forms/ensure/user.js +45 -0
  233. package/dist/services/forms/index.js +138 -0
  234. package/dist/services/migrations/ensure/notifications.js +189 -0
  235. package/dist/services/migrations/ensure/orders.js +34 -0
  236. package/dist/services/migrations/ensure/payment-provider.js +132 -0
  237. package/dist/services/migrations/ensure/payments-intents.js +34 -0
  238. package/dist/services/migrations/ensure/state-retirement.js +266 -0
  239. package/dist/services/migrations/ensure/targets-rename.js +124 -0
  240. package/dist/services/migrations/ensure/users.js +1176 -0
  241. package/dist/services/migrations/index.js +101 -0
  242. package/dist/services/migrations/lib/attribution-touch.js +64 -0
  243. package/dist/services/migrations/lib/ensure-metadata.js +144 -0
  244. package/dist/services/migrations/lib/migration-runner.js +473 -0
  245. package/dist/services/migrations/lib/sanitize-strings.js +112 -0
  246. package/dist/services/migrations/lib/schema-validator.js +154 -0
  247. package/dist/services/monitoring/ensure/dsn.js +54 -0
  248. package/dist/services/monitoring/ensure/projects.js +135 -0
  249. package/dist/services/monitoring/index.js +54 -0
  250. package/dist/services/monitoring/lib/sentry-api.js +94 -0
  251. package/dist/services/newsletter/ensure/custom-fields.js +90 -0
  252. package/dist/services/newsletter/ensure/publication.js +94 -0
  253. package/dist/services/newsletter/ensure/segments.js +140 -0
  254. package/dist/services/newsletter/ensure/webhook.js +108 -0
  255. package/dist/services/newsletter/index.js +64 -0
  256. package/dist/services/newsletter/lib/beehiiv-api.js +124 -0
  257. package/dist/services/newsletter/lib/segment-automation.js +577 -0
  258. package/dist/services/payment/ensure/chargebee-account.js +30 -0
  259. package/dist/services/payment/ensure/chargebee-products.js +359 -0
  260. package/dist/services/payment/ensure/chargebee-webhook.js +113 -0
  261. package/dist/services/payment/ensure/paypal-account.js +36 -0
  262. package/dist/services/payment/ensure/paypal-products.js +374 -0
  263. package/dist/services/payment/ensure/paypal-webhook.js +128 -0
  264. package/dist/services/payment/ensure/stripe-account.js +93 -0
  265. package/dist/services/payment/ensure/stripe-disputes.js +56 -0
  266. package/dist/services/payment/ensure/stripe-products.js +245 -0
  267. package/dist/services/payment/ensure/stripe-radar.js +74 -0
  268. package/dist/services/payment/ensure/stripe-webhook.js +130 -0
  269. package/dist/services/payment/index.js +163 -0
  270. package/dist/services/payment/lib/chargebee-api.js +338 -0
  271. package/dist/services/payment/lib/payment-utils.js +116 -0
  272. package/dist/services/payment/lib/paypal-api.js +354 -0
  273. package/dist/services/payment/lib/provider-setup.js +134 -0
  274. package/dist/services/payment/lib/stripe-api.js +152 -0
  275. package/dist/services/repo/ensure/org.js +70 -0
  276. package/dist/services/repo/ensure/pages.js +72 -0
  277. package/dist/services/repo/ensure/repo.js +90 -0
  278. package/dist/services/repo/index.js +52 -0
  279. package/dist/services/repo/lib/github-api.js +196 -0
  280. package/dist/services/search/ensure/ga-link.js +57 -0
  281. package/dist/services/search/ensure/property.js +137 -0
  282. package/dist/services/search/ensure/sitemaps.js +70 -0
  283. package/dist/services/search/index.js +61 -0
  284. package/dist/services/search/lib/search-console-api.js +92 -0
  285. package/dist/services/seo/ensure/github-repos.js +271 -0
  286. package/dist/services/seo/index.js +55 -0
  287. package/dist/services/seo/lib/gh-api.js +161 -0
  288. package/dist/services/seo/templates/developer-tool/.github/workflows/maintenance.yml +25 -0
  289. package/dist/services/seo/templates/developer-tool/.nvmrc +1 -0
  290. package/dist/services/seo/templates/developer-tool/_README.md.js +121 -0
  291. package/dist/services/seo/templates/developer-tool/_package.json.js +33 -0
  292. package/dist/services/seo/templates/developer-tool/src/index.js +120 -0
  293. package/dist/services/seo/templates/index.js +57 -0
  294. package/dist/services/server/ensure/brands.js +63 -0
  295. package/dist/services/server/index.js +42 -0
  296. package/dist/services/testing/ensure/target-checks.js +97 -0
  297. package/dist/services/testing/index.js +11 -0
  298. package/dist/services/testing/lib/checks.js +467 -0
  299. package/dist/services/update/index.js +20 -0
  300. package/dist/services/update/lib/cache.js +59 -0
  301. package/dist/services/update/lib/fingerprint.js +157 -0
  302. package/dist/services/update/write/targets.js +206 -0
  303. package/dist/services/workspace/ensure/agents.js +42 -0
  304. package/dist/services/workspace/ensure/claude-settings.js +34 -0
  305. package/dist/services/workspace/ensure/config.js +54 -0
  306. package/dist/services/workspace/ensure/defaults.js +60 -0
  307. package/dist/services/workspace/ensure/env-keys.js +55 -0
  308. package/dist/services/workspace/ensure/env-order.js +66 -0
  309. package/dist/services/workspace/ensure/env-rules.js +97 -0
  310. package/dist/services/workspace/ensure/gitignore.js +18 -0
  311. package/dist/services/workspace/ensure/scripts.js +126 -0
  312. package/dist/services/workspace/ensure/structure.js +97 -0
  313. package/dist/services/workspace/ensure/translation-sdk.js +148 -0
  314. package/dist/services/workspace/ensure/workflows.js +54 -0
  315. package/dist/services/workspace/index.js +8 -0
  316. package/dist/vendor/account/engine.js +182 -0
  317. package/dist/vendor/account/features.js +220 -0
  318. package/dist/vendor/account/index.js +53 -0
  319. package/dist/vendor/account/schema.js +272 -0
  320. package/dist/vendor/account/subscription.js +38 -0
  321. package/dist/vendor/config/company.js +31 -0
  322. package/dist/vendor/config/defaults.js +173 -0
  323. package/dist/vendor/config/demo.js +18 -0
  324. package/dist/vendor/config/desktop-artifacts.js +110 -0
  325. package/dist/vendor/config/edit.js +769 -0
  326. package/dist/vendor/config/env-delivery.js +145 -0
  327. package/dist/vendor/config/env-rules.js +93 -0
  328. package/dist/vendor/config/env-schema.js +1078 -0
  329. package/dist/vendor/config/env.js +445 -0
  330. package/dist/vendor/config/hooks.js +97 -0
  331. package/dist/vendor/config/index.js +237 -0
  332. package/dist/vendor/config/instances.js +208 -0
  333. package/dist/vendor/config/load.js +490 -0
  334. package/dist/vendor/config/merge.js +68 -0
  335. package/dist/vendor/config/order.js +139 -0
  336. package/dist/vendor/config/ports.js +374 -0
  337. package/dist/vendor/config/providers.js +32 -0
  338. package/dist/vendor/config/repo.js +142 -0
  339. package/dist/vendor/config/retired-keys.js +430 -0
  340. package/dist/vendor/config/schema.js +1610 -0
  341. package/dist/vendor/config/secrets.js +50 -0
  342. package/dist/vendor/config/seed.js +34 -0
  343. package/dist/vendor/config/site-global.js +205 -0
  344. package/dist/vendor/config/validate.js +554 -0
  345. package/dist/vendor/config/winback.js +61 -0
  346. package/dist/vendor/devkit/attach-log-file.js +262 -0
  347. package/dist/vendor/devkit/certs.js +199 -0
  348. package/dist/vendor/devkit/ci-workflows.js +520 -0
  349. package/dist/vendor/devkit/cli-router.js +156 -0
  350. package/dist/vendor/devkit/command-path.js +46 -0
  351. package/dist/vendor/devkit/deploy-record.js +180 -0
  352. package/dist/vendor/devkit/flows.js +317 -0
  353. package/dist/vendor/devkit/local-https.js +360 -0
  354. package/dist/vendor/devkit/local.js +1905 -0
  355. package/dist/vendor/devkit/logger.js +128 -0
  356. package/dist/vendor/devkit/omega-bin.js +345 -0
  357. package/dist/vendor/devkit/prompt.js +187 -0
  358. package/dist/vendor/devkit/safe-install.js +18 -0
  359. package/dist/vendor/devkit/stop-signals.js +28 -0
  360. package/dist/vendor/devkit/test/scope.js +162 -0
  361. package/dist/vendor/devkit/translate/cache.js +84 -0
  362. package/dist/vendor/devkit/translate/engine.js +243 -0
  363. package/dist/vendor/devkit/translate/index.js +49 -0
  364. package/dist/vendor/devkit/translate/languages.js +134 -0
  365. package/dist/vendor/devkit/translate/providers.js +188 -0
  366. package/dist/vendor/devkit/update.js +569 -0
  367. package/docs/AGENTS.md +200 -0
  368. package/docs/account.md +45 -0
  369. package/docs/advertising.md +46 -0
  370. package/docs/ai.md +34 -0
  371. package/docs/analytics.md +69 -0
  372. package/docs/assets.md +57 -0
  373. package/docs/bookmark.md +26 -0
  374. package/docs/brand.md +151 -0
  375. package/docs/campaigns.md +96 -0
  376. package/docs/captcha.md +46 -0
  377. package/docs/certificates.md +68 -0
  378. package/docs/chat.md +47 -0
  379. package/docs/cloud.md +110 -0
  380. package/docs/company.md +64 -0
  381. package/docs/directory.md +140 -0
  382. package/docs/disperse.md +46 -0
  383. package/docs/domain.md +56 -0
  384. package/docs/edge.md +234 -0
  385. package/docs/email.md +42 -0
  386. package/docs/forms.md +48 -0
  387. package/docs/index.md +109 -0
  388. package/docs/migration.md +203 -0
  389. package/docs/migrations.md +56 -0
  390. package/docs/monitoring.md +41 -0
  391. package/docs/newsletter.md +48 -0
  392. package/docs/payment.md +83 -0
  393. package/docs/repo.md +48 -0
  394. package/docs/search.md +44 -0
  395. package/docs/seo.md +34 -0
  396. package/docs/server.md +37 -0
  397. package/docs/shared/agent-docs.md +89 -0
  398. package/docs/shared/analytics.md +612 -0
  399. package/docs/shared/brands.md +51 -0
  400. package/docs/shared/breaking-changes.md +497 -0
  401. package/docs/shared/config.md +1387 -0
  402. package/docs/shared/deploys.md +215 -0
  403. package/docs/shared/icons.md +201 -0
  404. package/docs/shared/local-dev.md +147 -0
  405. package/docs/shared/logging.md +202 -0
  406. package/docs/shared/monitoring.md +153 -0
  407. package/docs/shared/publishing.md +183 -0
  408. package/docs/shared/rulings.md +34 -0
  409. package/docs/shared/testing.md +147 -0
  410. package/docs/shared/theming.md +604 -0
  411. package/docs/shared/translation.md +291 -0
  412. package/docs/shared/updates.md +61 -0
  413. package/docs/testing.md +34 -0
  414. package/docs/update.md +36 -0
  415. package/docs/workspace.md +64 -0
  416. package/package.json +88 -0
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Devlog backlink SSOT — map every known brand repo to its public project
3
+ * (name + URL) so the writer can link each mentioned repo to the product it
4
+ * belongs to. Repos not in the map are treated as standalone and linked to
5
+ * GitHub instead.
6
+ *
7
+ * In the brand-monorepo world every brand is ONE repo, addressed by
8
+ * `@omega.js/config`'s `brandRepo` — the typed `repo.providers.github.repo` slug
9
+ * (whose owner half wins when it carries one), else `<brand.id>-omega` under
10
+ * `repo.providers.github.org`, the ONE derivation the github service reads too;
11
+ * omega-manager's per-target + subdomain repo fan-out collapsed at the
12
+ * redesign. Brands without a repo.providers.github.org are skipped (the github service
13
+ * skips them too).
14
+ */
15
+
16
+ const { brandRepo: deriveBrandRepo, brandRepoName } = require('../../vendor/config/index.js');
17
+
18
+ /**
19
+ * Resolve a loaded brand's repo identity, or null when it has none.
20
+ *
21
+ * @param {object} brand - Loaded brand (lib/brand.js loadBrand shape)
22
+ * @returns {{ owner: string, repo: string }|null}
23
+ */
24
+ function brandRepo(brand) {
25
+ const github = brand.config.repo?.providers?.github;
26
+
27
+ if (!github.org) {
28
+ return null;
29
+ }
30
+
31
+ // BOTH halves from the one derivation: an `owner/name` slug houses the repo
32
+ // under its own owner. The loaded brand's own id stands in for a config that
33
+ // names none.
34
+ const { owner, name } = deriveBrandRepo(brand.config);
35
+
36
+ return { owner, repo: name || brandRepoName({ brand: { id: brand.id } }) };
37
+ }
38
+
39
+ /**
40
+ * Build the repo → project map across every loaded brand.
41
+ *
42
+ * @param {Array} brands - Loaded brands
43
+ * @param {object} [params] - { excludeRepos }
44
+ * @returns {Object<string, {project: string, url: string}>} repoName → project
45
+ */
46
+ function buildProjectMap(brands, { excludeRepos = [] } = {}) {
47
+ const map = {};
48
+
49
+ for (const brand of brands) {
50
+ const identity = brandRepo(brand);
51
+
52
+ if (!identity || excludeRepos.includes(identity.repo)) {
53
+ continue;
54
+ }
55
+
56
+ map[identity.repo] = {
57
+ project: brand.config.brand?.name || brand.id,
58
+ url: brand.config.brand?.url || '',
59
+ };
60
+ }
61
+
62
+ return map;
63
+ }
64
+
65
+ /**
66
+ * Build the complete brand repo list. The brand configs are the SSOT for
67
+ * where every repo lives, so scanning is never limited to the hand-maintained
68
+ * `orgs` list — that list only supplements this with non-brand repos
69
+ * (frameworks, tooling).
70
+ *
71
+ * @param {Array} brands - Loaded brands
72
+ * @param {object} [params] - { excludeRepos }
73
+ * @returns {Array<{ owner: string, repo: string }>} Unique owner/repo pairs
74
+ */
75
+ function buildBrandRepos(brands, { excludeRepos = [] } = {}) {
76
+ const seen = new Set();
77
+ const repos = [];
78
+
79
+ for (const brand of brands) {
80
+ const identity = brandRepo(brand);
81
+
82
+ if (!identity || excludeRepos.includes(identity.repo)) {
83
+ continue;
84
+ }
85
+
86
+ const key = `${identity.owner}/${identity.repo}`.toLowerCase();
87
+ if (seen.has(key)) {
88
+ continue;
89
+ }
90
+
91
+ seen.add(key);
92
+ repos.push(identity);
93
+ }
94
+
95
+ return repos;
96
+ }
97
+
98
+ module.exports = { buildProjectMap, buildBrandRepos };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Devlog publish stage — write the post into the brand's website target and
3
+ * push it live. In the brand-monorepo world the website is a target INSIDE the brand
4
+ * repo (targets/{website}/src), so the commit lands in the brand monorepo itself.
5
+ * Publishing IS the push — the site auto-builds and deploys on push. Only the
6
+ * post file is committed; unrelated dirty files are untouched.
7
+ */
8
+
9
+ const { execSync } = require('node:child_process');
10
+ const { join } = require('node:path');
11
+
12
+ const jetpack = require('fs-jetpack');
13
+
14
+ /**
15
+ * Local YYYY-MM-DD stamp — local (not UTC) so a late-night run never
16
+ * future-dates the post, which the site build would silently skip.
17
+ *
18
+ * @param {Date} date - Date to stamp
19
+ * @returns {string} YYYY-MM-DD
20
+ */
21
+ function localDateStamp(date) {
22
+ const year = date.getFullYear();
23
+ const month = String(date.getMonth() + 1).padStart(2, '0');
24
+ const day = String(date.getDate()).padStart(2, '0');
25
+
26
+ return `${year}-${month}-${day}`;
27
+ }
28
+
29
+ /**
30
+ * Render the post file (blueprint front matter + markdown body).
31
+ *
32
+ * @param {object} brandConfig - Merged brand config
33
+ * @param {object} post - Generated post { title, slug, description, tags, categories, body }
34
+ * @returns {string} Full post file contents
35
+ */
36
+ function renderPostFile(brandConfig, post) {
37
+ return [
38
+ '---',
39
+ 'layout: blueprint/blog/post',
40
+ '',
41
+ 'post:',
42
+ ` title: ${JSON.stringify(post.title)}`,
43
+ ` description: ${JSON.stringify(post.description)}`,
44
+ ` author: ${brandConfig.brand.id}`,
45
+ ` id: ${Math.floor(Date.now() / 1000)}`,
46
+ ` tags: ${JSON.stringify(post.tags)}`,
47
+ ` categories: ${JSON.stringify(post.categories)}`,
48
+ '---',
49
+ '',
50
+ post.body,
51
+ '',
52
+ ].join('\n');
53
+ }
54
+
55
+ /**
56
+ * Write the post into the brand's website target, commit only the post file in
57
+ * the brand monorepo, and push.
58
+ *
59
+ * @param {object} params - { brand, post } (brand = lib/brand.js loadBrand shape)
60
+ * @returns {{ postPath: string, url: string }} Written file + eventual live URL
61
+ */
62
+ function publishToWebsite({ brand, post }) {
63
+ const webTarget = brand.targets.find((entry) => entry.target === 'web');
64
+
65
+ if (!webTarget) {
66
+ throw new Error(`Brand ${brand.id} has no website target under targets/ — devlog's 'website' destination needs one`);
67
+ }
68
+
69
+ const now = new Date();
70
+ const date = localDateStamp(now);
71
+ const relativePath = join(webTarget.dir, 'src', '_posts', String(now.getFullYear()), brand.config.devlog.providers.ghostii.postPath, `${date}-${post.slug}.md`);
72
+ const postPath = join(brand.root, relativePath);
73
+
74
+ jetpack.write(postPath, renderPostFile(brand.config, post));
75
+
76
+ const git = (args) => execSync(`git ${args}`, { cwd: brand.root, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
77
+
78
+ git(`add "${relativePath}"`);
79
+ git(`commit -m "📦 Omega: Add devlog post ${date}-${post.slug}" -- "${relativePath}"`);
80
+ git('push');
81
+
82
+ return {
83
+ postPath,
84
+ url: `${brand.config.brand.url}/blog/${post.slug}`,
85
+ };
86
+ }
87
+
88
+ module.exports = { publishToWebsite, renderPostFile };
package/dist/index.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @omega.js/manager — the OMEGA orchestration engine for brand monorepos.
3
+ * Public surface: the manage runner, the service-runner factory (services
4
+ * and tests build on it), brand loading, and the registry.
5
+ */
6
+
7
+ const { runManage } = require('./manage.js');
8
+ const { createServiceRunner, splitReturn, getOperationHandler } = require('./lib/service-runner.js');
9
+ const { RunSummary } = require('./lib/run-summary.js');
10
+ const { resolveBrandRoot, loadBrand, discoverTargets, targetFromDirName } = require('./lib/brand.js');
11
+ const { writeRunOutput } = require('./lib/run-output.js');
12
+ const {
13
+ SERVICE_ORDER,
14
+ OPERATIONS,
15
+ DEFAULTS,
16
+ DIR_TARGETS,
17
+ TARGET_DIRS,
18
+ templateObject,
19
+ } = require('./config.js');
20
+
21
+ module.exports = {
22
+ // Orchestrator
23
+ runManage,
24
+
25
+ // Service framework
26
+ createServiceRunner,
27
+ splitReturn,
28
+ getOperationHandler,
29
+ RunSummary,
30
+
31
+ // Brand + run output
32
+ resolveBrandRoot,
33
+ loadBrand,
34
+ discoverTargets,
35
+ targetFromDirName,
36
+ writeRunOutput,
37
+
38
+ // Registry
39
+ SERVICE_ORDER,
40
+ OPERATIONS,
41
+ DEFAULTS,
42
+ DIR_TARGETS,
43
+ TARGET_DIRS,
44
+ templateObject,
45
+ };
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Brand agent-docs chain (Ian 2026-07-20, amended 2026-07-27): every brand
3
+ * root carries an AGENTS.md whose FIRST line imports the TOP-LEVEL omega
4
+ * AGENTS.md — the map, the one agent entry — through the scope path
5
+ * `node_modules/@omega.js/AGENTS.md`, plus a one-line CLAUDE.md pointer
6
+ * (`@AGENTS.md`). The scope file is a symlink this service maintains: it
7
+ * resolves the framework monorepo through the installed manager package and
8
+ * links straight at the live top-level map; a published install has no
9
+ * monorepo, so it links at the map the prepare lane vendored into the package
10
+ * (`docs/AGENTS.md`). Idempotent: create when missing, heal a missing/stale
11
+ * first-line import in place, never touch consumer content below the import.
12
+ */
13
+ const { join, dirname } = require('node:path');
14
+ const fs = require('node:fs');
15
+ const jetpack = require('fs-jetpack');
16
+
17
+ const GUIDE_SUBPATH = 'node_modules/@omega.js/AGENTS.md';
18
+ const IMPORT_LINE = `@${GUIDE_SUBPATH}`;
19
+ const CLAUDE_POINTER = '@AGENTS.md';
20
+
21
+ const SCOPE_PREFIXES = ['', '../', '../../', '../../../'];
22
+
23
+ /**
24
+ * Is this line an import of the framework guide (any relative depth)?
25
+ *
26
+ * @param {string} line - A single file line
27
+ * @returns {boolean}
28
+ */
29
+ function isImportLine(line) {
30
+ const trimmed = line.trim();
31
+ return trimmed.startsWith('@') && trimmed.endsWith(GUIDE_SUBPATH);
32
+ }
33
+
34
+ /**
35
+ * The @omega.js scope directory serving this brand: the brand's own
36
+ * node_modules normally, an ancestor's when hoisted (npm workspaces).
37
+ *
38
+ * @param {string} brandRoot - Absolute brand monorepo root
39
+ * @returns {{prefix: string, scopeDir: string}|null}
40
+ */
41
+ function findScope(brandRoot) {
42
+ for (const prefix of SCOPE_PREFIXES) {
43
+ const scopeDir = join(brandRoot, prefix, 'node_modules', '@omega.js');
44
+ if (jetpack.exists(scopeDir) !== 'dir') continue;
45
+ // Only a scope that can back the import counts: the map link is already
46
+ // there, or the manager package is present for ensureGuideLink to resolve
47
+ // it. An empty dir from a partial install would leave the import dangling
48
+ // while the real scope sits a level up (#153).
49
+ if (jetpack.exists(join(scopeDir, 'AGENTS.md')) !== false
50
+ || jetpack.exists(join(scopeDir, 'manager')) !== false) {
51
+ return { prefix, scopeDir };
52
+ }
53
+ }
54
+ return null;
55
+ }
56
+
57
+ /**
58
+ * Resolve the import line for THIS brand — the depth that reaches the scope
59
+ * directory holding `@omega.js/AGENTS.md`. Falls back to the canonical
60
+ * brand-local path when nothing is installed yet (pre-install).
61
+ *
62
+ * @param {string} brandRoot - Absolute brand monorepo root
63
+ * @returns {string} - The `@<relative path>` import line
64
+ */
65
+ function resolveImportLine(brandRoot) {
66
+ const scope = findScope(brandRoot);
67
+ return scope ? `@${scope.prefix}${GUIDE_SUBPATH}` : IMPORT_LINE;
68
+ }
69
+
70
+ /**
71
+ * Ensure `node_modules/@omega.js/AGENTS.md` links at the omega map. The
72
+ * installed manager package's real path (the local-era file: symlink) names
73
+ * both candidates, in this order: the monorepo's LIVE map two dirs up, then
74
+ * the copy the prepare lane vendors into the package (`docs/AGENTS.md`, #144).
75
+ * The live map wins wherever it exists, so a locally linked brand never lands
76
+ * on the generated copy sitting in that same monorepo's packages/manager.
77
+ * Neither present (pre-install) → the link is left alone and the step skips.
78
+ *
79
+ * @param {string} brandRoot - Absolute brand monorepo root
80
+ * @returns {'present'|'created'|'healed'|'skipped'} - What happened
81
+ */
82
+ function ensureGuideLink(brandRoot) {
83
+ const scope = findScope(brandRoot);
84
+ if (!scope) {
85
+ return 'skipped';
86
+ }
87
+
88
+ let mapFile;
89
+ try {
90
+ const managerReal = fs.realpathSync(join(scope.scopeDir, 'manager'));
91
+ mapFile = [
92
+ join(dirname(dirname(managerReal)), 'AGENTS.md'),
93
+ join(managerReal, 'docs', 'AGENTS.md'),
94
+ ].find((candidate) => jetpack.exists(candidate) === 'file');
95
+ } catch {
96
+ return 'skipped';
97
+ }
98
+ if (!mapFile) {
99
+ return 'skipped';
100
+ }
101
+
102
+ const linkPath = join(scope.scopeDir, 'AGENTS.md');
103
+ try {
104
+ if (fs.readlinkSync(linkPath) === mapFile) {
105
+ return 'present';
106
+ }
107
+ } catch {
108
+ // Not a symlink (missing, or a stale regular file) — fall through and place it.
109
+ }
110
+
111
+ const existed = jetpack.exists(linkPath) !== false;
112
+ jetpack.remove(linkPath);
113
+ fs.symlinkSync(mapFile, linkPath);
114
+ return existed ? 'healed' : 'created';
115
+ }
116
+
117
+ /**
118
+ * Render a fresh brand AGENTS.md.
119
+ *
120
+ * @param {string} brandName - Display name for the brand-notes heading
121
+ * @returns {string} - Full file content
122
+ */
123
+ function renderAgentsMd(brandName, importLine = IMPORT_LINE) {
124
+ return [
125
+ importLine,
126
+ '',
127
+ `# ${brandName} — brand notes`,
128
+ '',
129
+ ].join('\n');
130
+ }
131
+
132
+ /**
133
+ * Ensure the brand-root AGENTS.md exists with the framework import as its
134
+ * first line. Existing consumer content is preserved verbatim; a stray copy
135
+ * of the import lower in the file is removed when healing (no duplicates).
136
+ *
137
+ * @param {string} brandRoot - Absolute brand monorepo root
138
+ * @param {string} brandName - Display name used when creating fresh
139
+ * @returns {'present'|'created'|'healed'} - What happened
140
+ */
141
+ function ensureAgentsMd(brandRoot, brandName) {
142
+ const file = join(brandRoot, 'AGENTS.md');
143
+ const importLine = resolveImportLine(brandRoot);
144
+ const existing = jetpack.read(file);
145
+
146
+ if (existing === undefined) {
147
+ jetpack.write(file, renderAgentsMd(brandName, importLine));
148
+ return 'created';
149
+ }
150
+
151
+ const lines = existing.split('\n');
152
+ const hasCruft = lines.some((line, i) => i > 0 && isImportLine(line));
153
+
154
+ if (lines[0].trim() === importLine && !hasCruft) {
155
+ return 'present';
156
+ }
157
+
158
+ // Heal: the resolved import goes to the top; drop any stray/stale-depth
159
+ // import copy so heals never stack cruft
160
+ const body = lines.filter((line) => !isImportLine(line));
161
+ jetpack.write(file, [importLine, ...(body[0]?.trim() === '' ? [] : ['']), ...body].join('\n'));
162
+ return 'healed';
163
+ }
164
+
165
+ /**
166
+ * Ensure the brand-root CLAUDE.md is the one-line `@AGENTS.md` pointer.
167
+ * A content-bearing CLAUDE.md is NEVER clobbered — that content belongs in
168
+ * AGENTS.md (the caller warns with the move-it message).
169
+ *
170
+ * @param {string} brandRoot - Absolute brand monorepo root
171
+ * @returns {'present'|'created'|'content-bearing'} - What happened
172
+ */
173
+ function ensureClaudePointer(brandRoot) {
174
+ const file = join(brandRoot, 'CLAUDE.md');
175
+ const existing = jetpack.read(file);
176
+
177
+ if (existing === undefined) {
178
+ jetpack.write(file, `${CLAUDE_POINTER}\n`);
179
+ return 'created';
180
+ }
181
+
182
+ const meaningful = existing.split('\n').map((line) => line.trim()).filter(Boolean);
183
+ if (meaningful.includes(CLAUDE_POINTER)) {
184
+ return 'present';
185
+ }
186
+
187
+ return 'content-bearing';
188
+ }
189
+
190
+ module.exports = {
191
+ GUIDE_SUBPATH,
192
+ IMPORT_LINE,
193
+ CLAUDE_POINTER,
194
+ isImportLine,
195
+ findScope,
196
+ resolveImportLine,
197
+ ensureGuideLink,
198
+ renderAgentsMd,
199
+ ensureAgentsMd,
200
+ ensureClaudePointer,
201
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The brand-.env home of each target's GA4 Measurement Protocol secret — the
3
+ * ONE name the analytics service resolves from GA and writes. Per-target
4
+ * because every surface measures through its own stream; the per-target name
5
+ * is delivered as GOOGLE_ANALYTICS_SECRET on every verb (composed into
6
+ * dist/.env for backend, loaded into process.env for the others) — the env
7
+ * schema's rename, #678.
8
+ *
9
+ * It is a secret, so config/omega.json5 is not an option (the loader
10
+ * hard-fails secret-shaped keys) — before #434 it lived in .omega/state.json
11
+ * and the composition read it from there.
12
+ */
13
+
14
+ /**
15
+ * @param {string} target - Target key (web/backend/desktop/extension/mobile)
16
+ * @returns {string} The brand .env variable name, e.g. GOOGLE_ANALYTICS_SECRET_BACKEND
17
+ */
18
+ function streamSecretEnvName(target) {
19
+ return `GOOGLE_ANALYTICS_SECRET_${target.toUpperCase()}`;
20
+ }
21
+
22
+ module.exports = { streamSecretEnvName };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * argv shaping — the one rule about the leading VERB (#229).
3
+ *
4
+ * Every manager invocation now names its command (`omega manage --service=x`),
5
+ * so anything that REBUILDS an invocation from the raw argv — the run
6
+ * summary's copy-pasteable retry line, the company runner's per-brand child
7
+ * args — has to drop that verb first, or it doubles into `omega manage manage`.
8
+ */
9
+
10
+ /**
11
+ * The argv without its leading command verb. A first entry that starts with
12
+ * `-` is a flag, not a verb, and is left alone.
13
+ *
14
+ * @param {string[]} argv - Raw arguments (process.argv.slice(2) shaped).
15
+ * @returns {string[]} The arguments after the verb.
16
+ */
17
+ function stripLeadingVerb(argv) {
18
+ return argv[0] && !argv[0].startsWith('-') ? argv.slice(1) : argv;
19
+ }
20
+
21
+ module.exports = { stripLeadingVerb };
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Firebase Auth admin client over the Identity Toolkit REST API — the
3
+ * non-interactive replacement for omega-manager's firebase-admin
4
+ * `getAuth(brandId)`. Authenticates with the brand's own service account
5
+ * (.omega/secrets/service-account.json, provisioned by the firebase
6
+ * service) via the shared google-token provider; custom tokens are signed
7
+ * locally with the shared jwt helper, so there is no SDK dependency.
8
+ * Shared by the account service (required accounts) and the migrations
9
+ * service (orphaned-doc detection + creation-time reconciliation).
10
+ *
11
+ * Handlers call named methods, so tests fake this surface
12
+ * method-for-method. Lookups return null for missing users (instead of
13
+ * firebase-admin's auth/user-not-found throw).
14
+ */
15
+ const { createTokenProvider } = require('./google-token.js');
16
+ const { signJwt } = require('./jwt.js');
17
+
18
+ const IDENTITY_TOOLKIT_BASE = 'https://identitytoolkit.googleapis.com/v1';
19
+ const SCOPE = 'https://www.googleapis.com/auth/identitytoolkit';
20
+
21
+ // Fixed audience for Firebase custom tokens (not the project)
22
+ const CUSTOM_TOKEN_AUD = 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit';
23
+
24
+ /**
25
+ * Map an Identity Toolkit user record to the subset the services use.
26
+ * createdAt is Identity Toolkit's ms-since-epoch string; it surfaces as
27
+ * metadata.creationTime (ISO) to mirror firebase-admin's UserRecord shape.
28
+ */
29
+ function toUser(record) {
30
+ return {
31
+ uid: record.localId,
32
+ email: record.email,
33
+ providerData: (record.providerUserInfo || []).map((p) => ({ providerId: p.providerId })),
34
+ metadata: {
35
+ creationTime: record.createdAt ? new Date(Number(record.createdAt)).toISOString() : null,
36
+ },
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Create the auth admin client.
42
+ *
43
+ * @param {Object} serviceAccount - Parsed service-account JSON
44
+ * @returns {Object} { getUserByEmail, getUser, createUser, updateUser, createCustomToken }
45
+ */
46
+ function createAuthAdmin(serviceAccount) {
47
+ const projectId = serviceAccount.project_id;
48
+ const tokenProvider = createTokenProvider(serviceAccount, SCOPE);
49
+
50
+ async function request(method, body) {
51
+ const token = await tokenProvider.getAccessToken();
52
+
53
+ const response = await fetch(`${IDENTITY_TOOLKIT_BASE}/projects/${projectId}/${method}`, {
54
+ method: 'POST',
55
+ headers: {
56
+ 'Authorization': `Bearer ${token}`,
57
+ 'Content-Type': 'application/json',
58
+ },
59
+ body: JSON.stringify(body),
60
+ signal: AbortSignal.timeout(30000),
61
+ });
62
+
63
+ const data = await response.json();
64
+
65
+ if (!response.ok) {
66
+ throw new Error(`Identity Toolkit API error: ${data.error?.message || JSON.stringify(data)}`);
67
+ }
68
+
69
+ return data;
70
+ }
71
+
72
+ return {
73
+ /** Look up a user by email. Missing → null. */
74
+ async getUserByEmail(email) {
75
+ const data = await request('accounts:lookup', { email: [email] });
76
+ return data.users?.[0] ? toUser(data.users[0]) : null;
77
+ },
78
+
79
+ /** Look up a user by uid. Missing → null. */
80
+ async getUser(uid) {
81
+ const data = await request('accounts:lookup', { localId: [uid] });
82
+ return data.users?.[0] ? toUser(data.users[0]) : null;
83
+ },
84
+
85
+ /** Create a user with email + password. */
86
+ async createUser({ email, password }) {
87
+ const data = await request('accounts', { email, password });
88
+ return { uid: data.localId, email };
89
+ },
90
+
91
+ /** Update a user's password. */
92
+ async updateUser(uid, { password }) {
93
+ await request('accounts:update', { localId: uid, password });
94
+ },
95
+
96
+ /**
97
+ * Mint a Firebase custom token for a uid — signed locally with the
98
+ * service account's key (RS256), exchangeable for an ID token via the
99
+ * public signInWithCustomToken endpoint.
100
+ */
101
+ createCustomToken(uid) {
102
+ const now = Math.floor(Date.now() / 1000);
103
+
104
+ return signJwt(
105
+ { alg: 'RS256', typ: 'JWT' },
106
+ {
107
+ iss: serviceAccount.client_email,
108
+ sub: serviceAccount.client_email,
109
+ aud: CUSTOM_TOKEN_AUD,
110
+ iat: now,
111
+ exp: now + 3600,
112
+ uid,
113
+ },
114
+ serviceAccount.private_key,
115
+ );
116
+ },
117
+ };
118
+ }
119
+
120
+ module.exports = { createAuthAdmin, CUSTOM_TOKEN_AUD };