@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,126 @@
1
+ /**
2
+ * Ensure the brand's package.json scripts convention — the root AND each
3
+ * framework target's (npm scripts put node_modules/.bin on PATH, so plain
4
+ * `omega` resolves there). Script VALUES only — no other key or consumer
5
+ * content is ever touched. Idempotent: a converged file rewrites nothing.
6
+ *
7
+ * Root: `deploy: 'omega deploy'` guaranteed plus the start/manage migration
8
+ * (package-scripts.js). Targets: every key the framework declares in its own
9
+ * `projectScripts` is FRAMEWORK-owned and is rewritten to the default here,
10
+ * exactly as that framework's ensureTarget does on every verb run (#689) —
11
+ * one policy, two writers, so a consumer customizes behavior through hook
12
+ * points and never by editing a standard script. The walk running it at all
13
+ * is the onboard→dev cycle break (#675): the dev fan-out reaches those verbs
14
+ * THROUGH these scripts, so a freshly scaffolded target needs them before any
15
+ * verb has ever run. Keys the consumer added are never touched.
16
+ *
17
+ * The exceptions: a custom TARGET maps to no framework at all (#603), so it
18
+ * is skipped whole; a custom-server backend is skipped PER KEY (#584) — the
19
+ * verbs its mode refuses are the brand's own, named by the framework's
20
+ * `projectScriptsCustomOwned` declaration.
21
+ */
22
+ const { join } = require('node:path');
23
+ const jetpack = require('fs-jetpack');
24
+ const chalk = require('chalk').default;
25
+
26
+ const { healPackageScripts, syncTargetScripts } = require('../../../lib/package-scripts.js');
27
+ const { resolveFrameworkPackage } = require('../../../lib/framework-bin.js');
28
+ const { TARGET_FRAMEWORKS } = require('../../../config.js');
29
+ const { dryRunPlan } = require('../../../lib/run-gates.js');
30
+
31
+ module.exports = async ({ brandRoot, targets = [], options = {} }) => {
32
+ const pkgPath = join(brandRoot, 'package.json');
33
+ const raw = jetpack.read(pkgPath);
34
+ if (!raw) {
35
+ console.log(` ${chalk.dim('⊘ no root package.json yet (the structure operation scaffolds it)')}`);
36
+ return { output: { scripts: 'missing' } };
37
+ }
38
+
39
+ let pkg;
40
+ try {
41
+ pkg = JSON.parse(raw);
42
+ } catch (e) {
43
+ console.log(` ${chalk.yellow('⚠')} Root package.json doesn't parse (${e.message}) — fix it by hand`);
44
+ return { status: 'warned', reason: "root package.json doesn't parse", output: { scripts: 'unparseable' } };
45
+ }
46
+
47
+ const { scripts, changes } = healPackageScripts(pkg);
48
+
49
+ const targetWork = [];
50
+ const warnings = [];
51
+ for (const entry of targets) {
52
+ // A custom target's scripts are the brand's own contract (#603) — no
53
+ // framework declares them, so there is nothing to sync against
54
+ if (!entry.target) continue;
55
+
56
+ const framework = TARGET_FRAMEWORKS[entry.target];
57
+ const resolved = framework ? resolveFrameworkPackage(entry.path, framework) : null;
58
+ // Not installed yet (pre-`npm install`), or a framework that declares no
59
+ // projectScripts — nothing to fill from; the next walk heals it
60
+ if (!resolved || !resolved.pkg.projectScripts) continue;
61
+
62
+ const manifestPath = join(entry.path, 'package.json');
63
+ const targetRaw = jetpack.read(manifestPath);
64
+ if (!targetRaw) continue;
65
+
66
+ let targetPkg;
67
+ try {
68
+ targetPkg = JSON.parse(targetRaw);
69
+ } catch (e) {
70
+ console.log(` ${chalk.yellow('⚠')} ${entry.dir}/package.json doesn't parse (${e.message}) — fix it by hand`);
71
+ warnings.push(`${entry.dir}/package.json doesn't parse`);
72
+ continue;
73
+ }
74
+
75
+ // A custom-server backend owns the keys whose verbs its mode refuses
76
+ // (#584) — the framework declares WHICH, so no list lives here (#689)
77
+ const brandOwnedKeys = entry.projectType === 'custom' ? (resolved.pkg.projectScriptsCustomOwned || []) : [];
78
+
79
+ const synced = syncTargetScripts(targetPkg, resolved.pkg.projectScripts, brandOwnedKeys);
80
+ if (synced.changes.length) targetWork.push({ entry, manifestPath, targetPkg, synced });
81
+ }
82
+
83
+ if (!changes.length && !targetWork.length && !warnings.length) {
84
+ console.log(` ${chalk.green('✓')} Root + target scripts present`);
85
+ return null;
86
+ }
87
+
88
+ if (options.dryRun) {
89
+ const parts = [];
90
+ if (changes.length) parts.push(`heal root scripts (${changes.join(', ')})`);
91
+ for (const work of targetWork) {
92
+ parts.push(`sync ${work.entry.dir} scripts (${work.synced.changes.join(', ')})`);
93
+ }
94
+ return dryRunPlan(parts.join('; '), {
95
+ output: {
96
+ ...(changes.length ? { scripts: 'planned' } : {}),
97
+ ...(targetWork.length ? { targetScripts: 'planned' } : {}),
98
+ },
99
+ });
100
+ }
101
+
102
+ const output = {};
103
+
104
+ if (changes.length) {
105
+ pkg.scripts = scripts;
106
+ jetpack.write(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
107
+ console.log(` ${chalk.green('✓')} Healed root scripts \`${changes.join('`, `')}\``);
108
+ output.scripts = { changed: changes };
109
+ }
110
+
111
+ for (const work of targetWork) {
112
+ work.targetPkg.scripts = work.synced.scripts;
113
+ jetpack.write(work.manifestPath, `${JSON.stringify(work.targetPkg, null, 2)}\n`);
114
+ // The skipped keys are named per key: a custom-server backend's own verbs
115
+ // are absent by design, not by omission
116
+ const brandOwned = work.synced.skipped.length ? chalk.dim(` (brand-owned, untouched: ${work.synced.skipped.join(', ')})`) : '';
117
+ console.log(` ${chalk.green('✓')} Synced ${work.entry.dir} scripts \`${work.synced.changes.join('`, `')}\`${brandOwned}`);
118
+ output.targetScripts = output.targetScripts || {};
119
+ output.targetScripts[work.entry.name] = work.synced.changes;
120
+ }
121
+
122
+ return {
123
+ ...(warnings.length ? { status: 'warned', reason: warnings.join('; ') } : {}),
124
+ output,
125
+ };
126
+ };
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Ensure the brand-monorepo structure: a root package.json with targets/*
3
+ * workspaces, and a target directory for every enabled target. Dirs that map
4
+ * to no target are warned (never silently skipped); enabled targets with no
5
+ * dir are errors with the exact dir to create.
6
+ *
7
+ * Multi-instance targets: an ARRAY-form target expects one dir PER
8
+ * instance (`main` → the canonical dir, any other id → `<canonical>-<id>`) —
9
+ * an enabled instance without its dir is the same create-this-dir error. The
10
+ * single-object form keeps today's any-dir-of-the-type check untouched.
11
+ *
12
+ * Custom targets (#603) map to no framework by design, so they are checked BY
13
+ * DIR (the declaration names it) and never counted among the unmapped — this
14
+ * service is one of the two ops that see them at all.
15
+ */
16
+ const { join } = require('node:path');
17
+ const chalk = require('chalk').default;
18
+ const jetpack = require('fs-jetpack');
19
+
20
+ const { normalizeTargetInstances, instanceTargetDir, isCustomTargetEntry } = require('../../../vendor/config/index.js');
21
+ const { TARGET_DIRS } = require('../../../config.js');
22
+ const { customTargetDirs } = require('../../../lib/custom-target.js');
23
+
24
+ module.exports = async ({ brandRoot, brand, targets }) => {
25
+ const problems = [];
26
+ const findings = [];
27
+
28
+ // Root package.json must exist and declare targets/* workspaces
29
+ const pkg = jetpack.read(join(brandRoot, 'package.json'), 'json');
30
+ if (!pkg) {
31
+ problems.push('no package.json at the brand root');
32
+ } else {
33
+ const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : [];
34
+ if (!workspaces.includes('targets/*')) {
35
+ problems.push(`root package.json workspaces must include "targets/*" (found: ${JSON.stringify(workspaces)})`);
36
+ }
37
+ }
38
+
39
+ // Every enabled target needs at least one dir; the multi-instance array
40
+ // form needs every instance's exact dir (the config validator owns id
41
+ // sanity — malformed entries are its errors, never doubled here)
42
+ for (const target of brand.enabledTargets) {
43
+ const declared = brand.config?.targets?.[target];
44
+
45
+ // A custom target's dirs are named by its own declaration, one per
46
+ // instance — the same create-this-dir error, checked by name
47
+ if (isCustomTargetEntry(declared)) {
48
+ for (const dir of customTargetDirs({ targets: { [target]: declared } })) {
49
+ if (!targets.some((entry) => entry.name === dir)) {
50
+ problems.push(`enabled custom target "${target}" has no dir — create targets/${dir}/`);
51
+ }
52
+ }
53
+ continue;
54
+ }
55
+
56
+ if (Array.isArray(declared)) {
57
+ for (const instance of normalizeTargetInstances(declared)) {
58
+ if (typeof instance?.id !== 'string') continue;
59
+ const dir = instanceTargetDir(target, instance.id);
60
+ if (!targets.some((entry) => entry.name === dir)) {
61
+ problems.push(`enabled target "${target}" instance "${instance.id}" has no dir — create targets/${dir}/`);
62
+ }
63
+ }
64
+ continue;
65
+ }
66
+
67
+ if (!targets.some((entry) => entry.target === target)) {
68
+ const suggested = TARGET_DIRS[target] || target;
69
+ problems.push(`enabled target "${target}" has no dir — create targets/${suggested}/`);
70
+ }
71
+ }
72
+
73
+ // Dirs that resolve to no target are suspicious but not fatal — a DECLARED
74
+ // custom dir is neither: the brand said what it is
75
+ const unmapped = targets.filter((entry) => !entry.target && !entry.custom);
76
+ for (const entry of unmapped) {
77
+ findings.push(`${entry.dir} maps to no target — declare one in its omega.json5, use a conventional dir name, or declare it \`type: 'custom'\``);
78
+ }
79
+
80
+ if (problems.length > 0) {
81
+ for (const problem of problems) {
82
+ console.log(` ${chalk.red('✗')} ${problem}`);
83
+ }
84
+ return { status: 'error', error: problems.join('; '), output: { problems } };
85
+ }
86
+
87
+ console.log(` ${chalk.green('✓')} ${targets.length} target(s): ${targets.map((entry) => `${entry.name}→${entry.target || (entry.custom ? 'custom' : '?')}`).join(', ')}`);
88
+
89
+ if (findings.length > 0) {
90
+ for (const finding of findings) {
91
+ console.log(` ${chalk.yellow('⚠')} ${finding}`);
92
+ }
93
+ return { status: 'warned', reason: findings.join('; '), output: { findings } };
94
+ }
95
+
96
+ return { output: { targets: targets.map((entry) => ({ name: entry.name, target: entry.target })) } };
97
+ };
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Ensure a translating web target declares the Claude translation SDK (#168).
3
+ *
4
+ * `@omega.js/web` is the only framework that leaves `@anthropic-ai/claude-agent-sdk`
5
+ * to the consumer (#37: translation is opt-in and the SDK is heavy, so web
6
+ * declares it as an OPTIONAL PEER; backend and extension declare it as a real
7
+ * dependency). Every brand ends up translating (Ian 2026-08-03), so the manage
8
+ * cycle owns that install instead of a human typing it per brand: a web target
9
+ * whose resolved config turns translation on with the `claude` provider gets
10
+ * the dep written into its package.json and installed.
11
+ *
12
+ * Converge-to-config, same as every other workspace op: declared already =
13
+ * zero-mutation no-op (a consumer-chosen spec is never overwritten), dry run
14
+ * plans without writing, translation off or provider `chatgpt` = untouched.
15
+ * Disabling translation never REMOVES the dep (#168: uninstalling on a config
16
+ * flip is riskier than leaving it), and devkit's loud missing-SDK error stays
17
+ * the backstop for hand-managed brands.
18
+ */
19
+ const path = require('node:path');
20
+ const chalk = require('chalk').default;
21
+ const jetpack = require('fs-jetpack');
22
+
23
+ const { loadConfig } = require('../../../vendor/config/index.js');
24
+ const { resolveTranslationSettings } = require('../../../vendor/devkit/translate/index.js');
25
+ const { runCommand } = require('../../../lib/run-command.js');
26
+ const { dryRunPlan } = require('../../../lib/run-gates.js');
27
+
28
+ const SDK = '@anthropic-ai/claude-agent-sdk';
29
+
30
+ // Bootstrap range for a brand whose @omega.js/web isn't installed yet (a fresh
31
+ // clone's first manage). The authoritative copy is web's own optional peer
32
+ // (packages/web/package.json `peerDependencies`), read off the INSTALLED web
33
+ // package whenever it resolves, so the range always matches that version.
34
+ const FALLBACK_RANGE = '>=0.2';
35
+
36
+ /**
37
+ * The SDK range `@omega.js/web` declares as its optional peer, read from the
38
+ * target's installed copy via the node_modules climb (a manual walk, not
39
+ * require.resolve, because web's exports map doesn't expose its package.json).
40
+ *
41
+ * @param {string} targetPath - Absolute target root
42
+ * @returns {string} The declared peer range, or FALLBACK_RANGE when web isn't installed
43
+ */
44
+ function sdkRange(targetPath) {
45
+ let dir = path.resolve(targetPath);
46
+
47
+ while (true) {
48
+ const pkg = jetpack.read(path.join(dir, 'node_modules', '@omega.js', 'web', 'package.json'), 'json');
49
+ const range = pkg?.peerDependencies?.[SDK];
50
+ if (range) return range;
51
+
52
+ const parent = path.dirname(dir);
53
+ if (parent === dir) return FALLBACK_RANGE;
54
+ dir = parent;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Does this target's resolved config ask for the claude translation provider?
60
+ * devkit's resolver is the SSOT for the section's defaults (absent `enabled`
61
+ * is on, an absent `providers` block is claude, no languages is off).
62
+ *
63
+ * @param {object} entry - Discovered target dir ({ path, target, ... })
64
+ * @returns {boolean}
65
+ */
66
+ function wantsClaudeTranslation(entry) {
67
+ const { config } = loadConfig(entry.path, entry.target);
68
+ const settings = resolveTranslationSettings(config);
69
+
70
+ return settings.enabled && settings.provider === 'claude';
71
+ }
72
+
73
+ module.exports = async ({ brandRoot, targets, options = {}, runCommand: run = runCommand }) => {
74
+ const drifted = [];
75
+ const findings = [];
76
+
77
+ for (const entry of targets.filter((item) => item.target === 'web')) {
78
+ let wanted;
79
+ try {
80
+ wanted = wantsClaudeTranslation(entry);
81
+ } catch (error) {
82
+ // An unreadable translation section (an unknown language code, say) is an
83
+ // TARGET-level finding, so it warns and leaves that target alone rather than
84
+ // halting the whole manage walk (the sibling convention stated in
85
+ // ensure/config.js). The web target's own translate run is the hard gate.
86
+ const finding = `${entry.name}: ${error.message}`;
87
+ console.log(` ${chalk.yellow('⚠')} ${finding}`);
88
+ findings.push(finding);
89
+ continue;
90
+ }
91
+
92
+ if (!wanted) continue;
93
+
94
+ const pkgPath = path.join(entry.path, 'package.json');
95
+ const pkg = jetpack.read(pkgPath, 'json');
96
+ if (!pkg) {
97
+ console.log(` ${chalk.dim(`⊘ ${entry.name}: no package.json yet`)}`);
98
+ continue;
99
+ }
100
+
101
+ if (pkg.dependencies?.[SDK] || pkg.devDependencies?.[SDK]) continue;
102
+
103
+ drifted.push({ entry, pkgPath, pkg, range: sdkRange(entry.path) });
104
+ }
105
+
106
+ // Any finding warns the operation, whatever the drift work on the readable
107
+ // targets returned
108
+ const withFindings = (result) => (findings.length === 0
109
+ ? result
110
+ : { ...result, status: 'warned', reason: result?.reason || findings.join('; '), output: { ...result?.output, findings } });
111
+
112
+ if (drifted.length === 0) {
113
+ if (findings.length === 0) console.log(` ${chalk.green('✓')} Translation SDK converged`);
114
+ return withFindings(null);
115
+ }
116
+
117
+ const summary = drifted.map(({ entry, range }) => `${entry.name}: ${SDK}@${range}`).join(', ');
118
+
119
+ if (options.dryRun) {
120
+ return withFindings(dryRunPlan(
121
+ `add the translation SDK (${summary}) and run npm install`,
122
+ { output: { translationSdk: 'planned' } },
123
+ ));
124
+ }
125
+
126
+ for (const { entry, pkgPath, pkg, range } of drifted) {
127
+ pkg.dependencies = { ...pkg.dependencies, [SDK]: range };
128
+ jetpack.write(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
129
+ console.log(` ${chalk.green('✓')} ${entry.name}: added ${SDK}@${range} (translation.providers.claude)`);
130
+ }
131
+
132
+ // One install at the brand root, since npm workspaces cover every target (the
133
+ // same shape the update service's install phase uses)
134
+ console.log(` ${chalk.dim('→')} npm install ${chalk.dim(`(${SDK})`)}`);
135
+ const result = await run('npm', ['install', '--no-audit', '--no-fund'], brandRoot);
136
+
137
+ const added = drifted.map(({ entry }) => entry.name);
138
+
139
+ if (!result.success) {
140
+ console.log(` ${chalk.yellow('⚠')} npm install failed (${result.error}); the dep is declared, so install it by hand`);
141
+ return withFindings({ status: 'warned', reason: 'npm install failed — install the SDK by hand', output: { translationSdk: { added, installed: false, error: result.error } } });
142
+ }
143
+
144
+ return withFindings({ output: { translationSdk: { added, installed: true } } });
145
+ };
146
+
147
+ // Exported for the drift-pin test: the bootstrap range must track web's peer
148
+ module.exports.FALLBACK_RANGE = FALLBACK_RANGE;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Reconcile the brand root's composed CI workflows (#636) — the ratified
3
+ * example of a dropped config key becoming a real removal: take
4
+ * `targets.extension` out of omega.json5 and the `extension-*.yml` files a
5
+ * previous manage composed at the brand root are DELETED on the next walk.
6
+ *
7
+ * The compose itself stays where it is, in each framework's own scaffold
8
+ * (`@omega.js/devkit/ci-workflows`), which is per-target by construction — and
9
+ * a dropped target's framework never runs again, so nothing there could ever
10
+ * clean up after it. The full enabled-target set is knowable in exactly one
11
+ * place, HERE: the workspace service already owns the brand root's own files
12
+ * and runs first in every walk, boot lane included.
13
+ *
14
+ * LIVE means the config still enables it, not that the dir is still on disk:
15
+ * removing `targets/<dir>` wholesale is deliberately out of scope (the dir
16
+ * mixes human app code), so the dir outlives the key and only the generated
17
+ * files go. Custom targets (`type: 'custom'`) are live whenever declared —
18
+ * they have no framework, so they compose nothing anyway.
19
+ *
20
+ * The deletion's own safety is devkit's double lock (the GENERATED header plus
21
+ * the composed naming): the brand's own hand-written workflows live in that
22
+ * same dir and are never candidates.
23
+ */
24
+ const chalk = require('chalk').default;
25
+
26
+ const { reconcileComposedWorkflows } = require('../../../vendor/devkit/ci-workflows.js');
27
+
28
+ module.exports = async ({ brandRoot, brand, targets, options }) => {
29
+ const dryRun = options?.dryRun || false;
30
+
31
+ const liveTargets = targets
32
+ .filter((entry) => entry.custom || (entry.target && brand.enabledTargets.includes(entry.target)))
33
+ .map((entry) => entry.name);
34
+
35
+ const { removed } = reconcileComposedWorkflows({
36
+ brandRoot,
37
+ liveTargets,
38
+ dryRun,
39
+ logger: { log: () => {}, warn: () => {} },
40
+ });
41
+
42
+ if (removed.length === 0) {
43
+ console.log(` ${chalk.green('✓')} Composed workflows match the enabled targets`);
44
+ return null;
45
+ }
46
+
47
+ if (dryRun) {
48
+ console.log(` ${chalk.yellow('[DRY RUN]')} Would remove ${chalk.cyan(removed.length)} composed workflow(s) for dropped targets: ${removed.join(', ')}`);
49
+ return { output: { workflows: { planned: removed.length } } };
50
+ }
51
+
52
+ console.log(` ${chalk.yellow('↺')} Removed ${chalk.bold(removed.length)} composed workflow(s) for dropped targets ${chalk.dim(`(${removed.join(', ')})`)}`);
53
+ return { output: { workflows: { removed: removed.length } } };
54
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Workspace service — the brand monorepo itself is the first thing the
3
+ * manager reconciles: root workspaces wiring, omega.json5 health, and the
4
+ * .omega/ gitignore entry. Everything downstream assumes a sane workspace.
5
+ */
6
+ const { createServiceRunner } = require('../../lib/service-runner.js');
7
+
8
+ module.exports.run = createServiceRunner({ serviceDir: __dirname });
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Schema resolution engine — extracted verbatim from @omega.js/backend's
3
+ * src/manager/helpers/user.js, with ONE change: the '$uuid'/'$randomId'/'$apiKey'
4
+ * value generators are injected via ctx.generators instead of being required
5
+ * in-module. Hosts that can generate them (@omega.js/backend, Node) inject real generators;
6
+ * hosts that can't (@omega.js/client, browser) pass none and the fields resolve to
7
+ * null — the doc's real values always come from the backend.
8
+ *
9
+ * The engine is environment-agnostic: no dependencies, no Node APIs.
10
+ */
11
+
12
+ /**
13
+ * Check if a schema node is a leaf field definition (has 'type' and 'default')
14
+ */
15
+ function isLeaf(node) {
16
+ return node !== null
17
+ && typeof node === 'object'
18
+ && typeof node.type === 'string'
19
+ && 'default' in node;
20
+ }
21
+
22
+ /**
23
+ * Coerce a value to the expected type. Returns the coerced value or undefined if coercion fails.
24
+ */
25
+ function coerce(value, type) {
26
+ if (typeof value === type) {
27
+ return value;
28
+ }
29
+
30
+ switch (type) {
31
+ case 'number': {
32
+ const n = Number(value);
33
+ return Number.isNaN(n) ? undefined : n;
34
+ }
35
+ case 'boolean': {
36
+ if (value === 'true' || value === 1) return true;
37
+ if (value === 'false' || value === 0) return false;
38
+ return Boolean(value);
39
+ }
40
+ case 'string': {
41
+ return String(value);
42
+ }
43
+ default: {
44
+ return undefined;
45
+ }
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Resolve a single leaf field value
51
+ */
52
+ function resolveLeaf(leaf, value, ctx) {
53
+ // Null handling
54
+ if (value === null) {
55
+ return leaf.nullable ? null : resolveDefault(leaf.default, ctx);
56
+ }
57
+
58
+ // Undefined → apply default
59
+ if (value === undefined) {
60
+ return resolveDefault(leaf.default, ctx);
61
+ }
62
+
63
+ // Array type — just check it's an array, don't coerce
64
+ if (leaf.type === 'array') {
65
+ return Array.isArray(value) ? value : resolveDefault(leaf.default, ctx);
66
+ }
67
+
68
+ // Type coercion
69
+ if (typeof value !== leaf.type) {
70
+ const coerced = coerce(value, leaf.type);
71
+ return coerced !== undefined ? coerced : resolveDefault(leaf.default, ctx);
72
+ }
73
+
74
+ return value;
75
+ }
76
+
77
+ /**
78
+ * Resolve a default value, handling special tokens
79
+ */
80
+ function resolveDefault(def, ctx) {
81
+ if (typeof def !== 'string' || !def.startsWith('$')) {
82
+ // For arrays, return a fresh copy to avoid shared references
83
+ if (Array.isArray(def)) {
84
+ return [...def];
85
+ }
86
+ return def;
87
+ }
88
+
89
+ switch (def) {
90
+ case '$uuid':
91
+ return ctx.generators.uuid ? ctx.generators.uuid() : null;
92
+ case '$randomId':
93
+ return ctx.generators.randomId ? ctx.generators.randomId() : null;
94
+ case '$apiKey':
95
+ return ctx.generators.apiKey ? ctx.generators.apiKey() : null;
96
+ case '$oldDate':
97
+ return ctx.oldDate;
98
+ case '$oldDateUNIX':
99
+ return ctx.oldDateUNIX;
100
+ case '$now':
101
+ return ctx.now;
102
+ case '$nowUNIX':
103
+ return ctx.nowUNIX;
104
+ default:
105
+ return def;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Expand $timestamp shorthand into a schema branch
111
+ */
112
+ function expandTimestamp(variant) {
113
+ const useNow = variant === '$timestamp:now';
114
+
115
+ return {
116
+ timestamp: { type: 'string', default: useNow ? '$now' : '$oldDate' },
117
+ timestampUNIX: { type: 'number', default: useNow ? '$nowUNIX' : 0 },
118
+ };
119
+ }
120
+
121
+ /**
122
+ * Recursively resolve a schema node against input data
123
+ */
124
+ function resolve(schema, data, ctx) {
125
+ data = data || {};
126
+ const result = {};
127
+
128
+ // If $passthrough, start by copying all existing keys from data
129
+ const isPassthrough = schema.$passthrough === true;
130
+ const template = schema.$template || null;
131
+
132
+ if (isPassthrough) {
133
+ // Copy all data keys first (they'll be overwritten by defined schema fields below)
134
+ for (const key of Object.keys(data)) {
135
+ if (template && !key.startsWith('$') && !(key in schema)) {
136
+ // Dynamic key — resolve against template
137
+ result[key] = resolve(template, data[key], ctx);
138
+ } else if (!(key in schema) || key.startsWith('$')) {
139
+ // Unknown key not in schema — passthrough as-is
140
+ result[key] = data[key];
141
+ }
142
+ }
143
+ }
144
+
145
+ // Now resolve each defined schema field
146
+ for (const [key, node] of Object.entries(schema)) {
147
+ // Skip meta keys
148
+ if (key.startsWith('$')) {
149
+ continue;
150
+ }
151
+
152
+ // Handle string shorthands
153
+ if (typeof node === 'string') {
154
+ if (node === '$template') {
155
+ // Resolve against parent's $template
156
+ result[key] = resolve(template, data[key], ctx);
157
+ continue;
158
+ }
159
+ if (node.startsWith('$timestamp')) {
160
+ // Expand timestamp shorthand and recurse
161
+ result[key] = resolve(expandTimestamp(node), data[key], ctx);
162
+ continue;
163
+ }
164
+ }
165
+
166
+ // Leaf field
167
+ if (isLeaf(node)) {
168
+ result[key] = resolveLeaf(node, data[key], ctx);
169
+ continue;
170
+ }
171
+
172
+ // Nested branch (plain object)
173
+ if (node !== null && typeof node === 'object') {
174
+ result[key] = resolve(node, data[key], ctx);
175
+ continue;
176
+ }
177
+ }
178
+
179
+ return result;
180
+ }
181
+
182
+ module.exports = { resolve };