@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,220 @@
1
+ /**
2
+ * features.js — the ONE reading of the features contract
3
+ * ([#647](https://github.com/Omega-JS-Stack/omega/issues/647)).
4
+ *
5
+ * A feature is DEFINED once, in the config's top-level `features` catalog:
6
+ *
7
+ * features: {
8
+ * saves: { name: 'Saves', icon: 'feather', definition: '…',
9
+ * usage: { pace: 'daily', mirror: ['teams'] } },
10
+ * support: { name: 'Priority support', icon: 'headset' },
11
+ * }
12
+ *
13
+ * A `usage` block makes the entry COUNTED (metered per user); an entry without
14
+ * one is a PERK, never counted. Each product then names only its VALUE:
15
+ * `features: { saves: 100, support: true }` — a number on a counted feature
16
+ * (the MONTHLY limit, -1 unlimited), true/false/a string on a perk.
17
+ *
18
+ * This module is the shared home of every derivation both sides make from
19
+ * those two halves plus a user's stored counters — the backend's `consume`
20
+ * gate and the browser's account page must never disagree about what a user's
21
+ * limit is:
22
+ * - the EFFECTIVE limit, where an admin-written `usage.overrides.<feature>`
23
+ * on the user doc wins over the plan's number;
24
+ * - the DAY share, `ceil(limit / days in this month)`, so a monthly quota
25
+ * cannot be burned on day one (pacing is the default; `pace: false` opts
26
+ * out to a plain monthly counter);
27
+ * - the two counters a counted feature carries per user, month and day.
28
+ *
29
+ * -1 is the unlimited sentinel everywhere it can appear: a limit, a day share,
30
+ * and a remaining count.
31
+ */
32
+
33
+ // Where a user's counters and overrides live on the account document.
34
+ const USAGE_KEY = 'usage';
35
+ const OVERRIDES_KEY = 'overrides';
36
+
37
+ /**
38
+ * Is this catalog entry COUNTED? A `usage` block is what meters a feature;
39
+ * everything else is a perk the plan either includes or does not.
40
+ * @param {object} entry - a top-level `features` catalog entry
41
+ * @returns {boolean}
42
+ */
43
+ function isCountedFeature(entry) {
44
+ return !!(entry && typeof entry === 'object' && entry.usage && typeof entry.usage === 'object' && !Array.isArray(entry.usage));
45
+ }
46
+
47
+ /**
48
+ * Is this feature paced by day? Pacing is the DEFAULT on every counted
49
+ * feature; `usage: { pace: false }` opts out to a plain monthly counter.
50
+ * @param {object} entry - a catalog entry
51
+ * @returns {boolean}
52
+ */
53
+ function isPacedFeature(entry) {
54
+ return isCountedFeature(entry) && entry.usage.pace !== false;
55
+ }
56
+
57
+ /**
58
+ * The document kinds a counted feature's counters mirror onto, declared in the
59
+ * catalog rather than at the call site.
60
+ * @param {object} entry - a catalog entry
61
+ * @returns {string[]} the declared kinds, or []
62
+ */
63
+ function featureMirrors(entry) {
64
+ return isCountedFeature(entry) && Array.isArray(entry.usage.mirror) ? entry.usage.mirror : [];
65
+ }
66
+
67
+ /**
68
+ * Days in the month the given date falls in.
69
+ * @param {Date} [date] - defaults to now
70
+ * @returns {number}
71
+ */
72
+ function daysInMonth(date) {
73
+ const d = date || new Date();
74
+ return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
75
+ }
76
+
77
+ /**
78
+ * A month limit's share of ONE day: ceil(limit / days in this month), so a
79
+ * quota of 100 in a 31-day month allows 4 a day and never 100 on the 1st.
80
+ * Unlimited stays unlimited; nothing stays nothing.
81
+ * @param {number} limit - the effective MONTHLY limit (-1 unlimited)
82
+ * @param {Date} [date] - the day being paced, defaults to now
83
+ * @returns {number} the day's share (-1 unlimited)
84
+ */
85
+ function dayShare(limit, date) {
86
+ if (!Number.isFinite(limit) || limit === 0) return 0;
87
+ if (limit < 0) return -1;
88
+ return Math.ceil(limit / daysInMonth(date));
89
+ }
90
+
91
+ /**
92
+ * The per-user override for a feature, when the account carries one. Written
93
+ * by admins only (the user doc's `usage` key is a framework field the security
94
+ * rules deny a client), and it WINS over the plan's number — extra credits
95
+ * granted to one account, not a second pricing tier.
96
+ * @param {object} account - the user document
97
+ * @param {string} id - feature id
98
+ * @returns {number|null} the override, or null when there is none
99
+ */
100
+ function featureOverride(account, id) {
101
+ const value = account && account[USAGE_KEY] && account[USAGE_KEY][OVERRIDES_KEY]
102
+ ? account[USAGE_KEY][OVERRIDES_KEY][id]
103
+ : undefined;
104
+
105
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
106
+ }
107
+
108
+ /**
109
+ * What a product promises for one feature: its raw value from the product's
110
+ * `features` map. A product that never names the feature promises nothing.
111
+ * @param {object} product - a `payment.products` entry
112
+ * @param {string} id - feature id
113
+ * @returns {*} the value, or undefined
114
+ */
115
+ function productFeatureValue(product, id) {
116
+ const values = product && product.features;
117
+ return values && typeof values === 'object' && !Array.isArray(values) ? values[id] : undefined;
118
+ }
119
+
120
+ /**
121
+ * The counters a user carries for one feature. The stored shape is
122
+ * `usage.<id>.{ monthly, daily, total, last }` — monthly and daily are the two
123
+ * the gate reads, total never resets, last records when it moved.
124
+ * @param {object} account - the user document
125
+ * @param {string} id - feature id
126
+ * @returns {{ monthly: number, daily: number, total: number }}
127
+ */
128
+ function featureCounters(account, id) {
129
+ const stored = (account && account[USAGE_KEY] && account[USAGE_KEY][id]) || {};
130
+ const read = (key) => (typeof stored[key] === 'number' && Number.isFinite(stored[key]) ? stored[key] : 0);
131
+
132
+ return { monthly: read('monthly'), daily: read('daily'), total: read('total') };
133
+ }
134
+
135
+ /**
136
+ * How many of a limit are left, given what is used. Unlimited stays unlimited.
137
+ * @param {number} limit - the limit (-1 unlimited)
138
+ * @param {number} used - the counter
139
+ * @returns {number} what remains (-1 unlimited), never below zero
140
+ */
141
+ function remaining(limit, used) {
142
+ if (limit < 0) return -1;
143
+ return Math.max(0, limit - used);
144
+ }
145
+
146
+ /**
147
+ * Resolve ONE feature against a catalog, a product and an account: everything
148
+ * a gate or an account page needs to speak about it in one object.
149
+ *
150
+ * @param {string} id - feature id
151
+ * @param {object} options
152
+ * @param {object} [options.catalog] - the top-level `features` catalog
153
+ * @param {object} [options.product] - the account's resolved product
154
+ * @param {object} [options.account] - the user document (counters + overrides)
155
+ * @param {Date} [options.now] - the day being paced, defaults to now
156
+ * @returns {object} { id, name, icon, definition, counted, paced, mirror,
157
+ * value, limit, planLimit, override, used, left, total,
158
+ * day: { limit, used, left } }
159
+ */
160
+ function resolveFeature(id, options) {
161
+ options = options || {};
162
+
163
+ const entry = (options.catalog || {})[id] || null;
164
+ const counted = isCountedFeature(entry);
165
+ const value = productFeatureValue(options.product, id);
166
+ const counters = featureCounters(options.account, id);
167
+ const override = featureOverride(options.account, id);
168
+
169
+ const planLimit = counted && typeof value === 'number' ? value : 0;
170
+ const limit = counted && override !== null ? override : planLimit;
171
+ const paced = isPacedFeature(entry);
172
+ const dayLimit = paced ? dayShare(limit, options.now) : -1;
173
+
174
+ return {
175
+ id: id,
176
+ name: (entry && entry.name) || id,
177
+ icon: (entry && entry.icon) || null,
178
+ definition: (entry && entry.definition) || null,
179
+ counted: counted,
180
+ paced: paced,
181
+ mirror: featureMirrors(entry),
182
+ value: counted ? limit : value,
183
+ limit: limit,
184
+ planLimit: planLimit,
185
+ override: override,
186
+ used: counters.monthly,
187
+ left: remaining(limit, counters.monthly),
188
+ total: counters.total,
189
+ day: {
190
+ limit: dayLimit,
191
+ used: counters.daily,
192
+ left: remaining(dayLimit, counters.daily),
193
+ },
194
+ };
195
+ }
196
+
197
+ /**
198
+ * Resolve every feature the catalog defines, in CATALOG order — the row order
199
+ * every surface renders (pricing rows, account bars).
200
+ * @param {object} options - same options as resolveFeature
201
+ * @returns {object[]} one resolved feature per catalog entry
202
+ */
203
+ function resolveFeatures(options) {
204
+ options = options || {};
205
+
206
+ return Object.keys(options.catalog || {}).map((id) => resolveFeature(id, options));
207
+ }
208
+
209
+ module.exports = {
210
+ isCountedFeature,
211
+ isPacedFeature,
212
+ featureMirrors,
213
+ featureOverride,
214
+ featureCounters,
215
+ productFeatureValue,
216
+ daysInMonth,
217
+ dayShare,
218
+ resolveFeature,
219
+ resolveFeatures,
220
+ };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @omega.js/account — the single source of truth for the OMEGA user/account schema.
3
+ *
4
+ * Today the account shape lives in two drifted places: @omega.js/backend's
5
+ * src/manager/helpers/user.js (canonical — schema engine + tokens) and
6
+ * @omega.js/client's DEFAULT_ACCOUNT in modules/auth.js (hand-rolled deep-merge,
7
+ * missing flags/activity/personal branches and `everPaid`). This package
8
+ * unifies them; each framework becomes a thin wrapper (@omega.js/backend keeps its
9
+ * `new User(Manager, settings).properties` API, @omega.js/client keeps
10
+ * `resolveAccount(rawData, firebaseUser)`).
11
+ *
12
+ * resolveAccount(data, options):
13
+ * options.generators — { uuid, randomId, apiKey } value generators for the
14
+ * '$uuid'/'$randomId'/'$apiKey' schema tokens. @omega.js/backend injects real ones
15
+ * (uuid v4, Utilities().randomId, uid-generator); the frontend passes none
16
+ * and the fields resolve to null (real values always come from the backend).
17
+ * options.user — optional auth-user overlay ({ uid, email }): fills
18
+ * account.auth identity when the doc doesn't carry it (@omega.js/client's
19
+ * resolveAccount(rawData, firebaseUser) semantic).
20
+ */
21
+ const USER_SCHEMA = require('./schema.js');
22
+ const { resolve } = require('./engine.js');
23
+ const resolveSubscription = require('./subscription.js');
24
+ const features = require('./features.js');
25
+
26
+ function resolveAccount(data, options) {
27
+ options = options || {};
28
+
29
+ // Time context — byte-identical to @omega.js/backend's node-powertools timestamps:
30
+ // powertools.timestamp(d, { output: 'string' }) === d.toISOString(),
31
+ // powertools.timestamp(d, { output: 'unix' }) === floor(ms / 1000).
32
+ const now = new Date();
33
+ const ctx = {
34
+ generators: options.generators || {},
35
+ now: now.toISOString(),
36
+ nowUNIX: Math.floor(now.getTime() / 1000),
37
+ oldDate: new Date(0).toISOString(),
38
+ oldDateUNIX: 0,
39
+ };
40
+
41
+ const account = resolve(USER_SCHEMA, data || {}, ctx);
42
+
43
+ // Auth-user overlay (frontend semantic): identity from the signed-in Firebase
44
+ // user when the stored doc doesn't already carry it
45
+ if (options.user) {
46
+ account.auth.uid = account.auth.uid || options.user.uid || null;
47
+ account.auth.email = account.auth.email || options.user.email || null;
48
+ }
49
+
50
+ return account;
51
+ }
52
+
53
+ module.exports = { USER_SCHEMA, resolveAccount, resolveSubscription, ...features };
@@ -0,0 +1,272 @@
1
+ /**
2
+ * USER_SCHEMA — the canonical OMEGA user/account schema (pure data, no logic).
3
+ *
4
+ * Extracted verbatim from @omega.js/backend's src/manager/helpers/user.js, which is
5
+ * the authoritative shape (@omega.js/client's DEFAULT_ACCOUNT had drifted from it).
6
+ *
7
+ * Each leaf field is { type, default, nullable }
8
+ * Special keys:
9
+ * $passthrough — preserve all existing keys from input, don't strip unknowns
10
+ * $template — shape applied to every dynamic key in a $passthrough object
11
+ * '$template' — (string value) reference to parent's $template
12
+ * '$timestamp' — shorthand for { timestamp, timestampUNIX } defaulting to epoch
13
+ * '$timestamp:now' — same but defaults to current time
14
+ * '$uuid', '$randomId', '$apiKey', '$oldDate' — resolved at runtime (generators
15
+ * are injected by the host — see engine.js; absent generators resolve to null)
16
+ */
17
+
18
+ /**
19
+ * One attribution TOUCH — a single visit's campaign context, shared by
20
+ * `attribution.first` and `attribution.last`
21
+ * ([#384](https://github.com/Omega-JS-Stack/omega/issues/384)). `tags` holds the
22
+ * utm set and `clickIds` the ad-platform click ids (fbclid/gclid/…), both
23
+ * passthrough because the platforms keep adding params. The schema is read-only
24
+ * to the engine, so one object serves both slots.
25
+ */
26
+ const ATTRIBUTION_TOUCH = {
27
+ tags: { $passthrough: true },
28
+ clickIds: { $passthrough: true },
29
+ referrer: { type: 'string', default: null, nullable: true },
30
+ url: { type: 'string', default: null, nullable: true },
31
+ page: { type: 'string', default: null, nullable: true },
32
+ timestamp: { type: 'string', default: null, nullable: true },
33
+ };
34
+
35
+ const USER_SCHEMA = {
36
+ auth: {
37
+ uid: { type: 'string', default: null, nullable: true },
38
+ email: { type: 'string', default: null, nullable: true },
39
+ temporary: { type: 'boolean', default: false },
40
+ },
41
+ subscription: {
42
+ product: {
43
+ id: { type: 'string', default: 'basic' },
44
+ name: { type: 'string', default: 'Basic' },
45
+ },
46
+ status: { type: 'string', default: 'active' },
47
+ expires: '$timestamp',
48
+ trial: {
49
+ claimed: { type: 'boolean', default: false },
50
+ expires: '$timestamp',
51
+ // How the trial ENDED: 'converted' | 'lapsed' | null (still running, or never
52
+ // answered). `claimed` says only that a trial happened — a converted trial and a
53
+ // lapsed one carry identical dates — so this is the one stored conversion signal.
54
+ // Stamped by the trial-lapse sweep once the provider confirms which it was.
55
+ outcome: { type: 'string', default: null, nullable: true },
56
+ },
57
+ cancellation: {
58
+ pending: { type: 'boolean', default: false },
59
+ date: '$timestamp',
60
+ },
61
+ payment: {
62
+ provider: { type: 'string', default: null, nullable: true },
63
+ orderId: { type: 'string', default: null, nullable: true },
64
+ resourceId: { type: 'string', default: null, nullable: true },
65
+ frequency: { type: 'string', default: null, nullable: true },
66
+ price: { type: 'number', default: 0 },
67
+ startDate: '$timestamp',
68
+ updatedBy: {
69
+ event: {
70
+ name: { type: 'string', default: null, nullable: true },
71
+ id: { type: 'string', default: null, nullable: true },
72
+ },
73
+ date: '$timestamp',
74
+ },
75
+ },
76
+ // The discount riding the subscription right now
77
+ // ([#325](https://github.com/Omega-JS-Stack/omega/issues/325)). Shaped as a
78
+ // discount-codes validate() RESULT — the one shape the whole payment stack
79
+ // already speaks — so the billing card reads exactly what the apply route
80
+ // wrote, and neither side learns a second spelling. `valid: false` (the
81
+ // default) IS "no discount": absent and denied read the same everywhere.
82
+ //
83
+ // Both shapes are always present and default to 0, unlike a fresh validate()
84
+ // result which omits the one it is not: this node is MERGED onto a document
85
+ // that may already carry a discount, and a percent claim landing on a stored
86
+ // amount would otherwise be read as the older, wrong number.
87
+ //
88
+ // `source` is what makes it safe to read as a CLAIM. Today only the winback
89
+ // claim writes this node; a code typed at checkout will set the same node
90
+ // when checkout starts writing it, and a winback pitch suppressed by someone
91
+ // else's promo is an offer silently withheld — so the node says which system
92
+ // applied it ('winback' | 'checkout'), and only 'winback' is the claimed
93
+ // signal the cancel flow gates on.
94
+ //
95
+ // `resourceId` is the subscription the discount was applied TO, stamped at
96
+ // claim time ([#333](https://github.com/Omega-JS-Stack/omega/issues/333)).
97
+ // It is what makes the node clearable: the unified webhook write carries no
98
+ // discount key, so a merge preserves this node forever, and a customer who
99
+ // churned and resubscribed carried a spent claim into the NEW subscription,
100
+ // where `source: 'winback'` reads as "already claimed" and silently retires
101
+ // an offer the backend would grant again. The webhook pipeline compares the
102
+ // stamp against the subscription each event is about and CLEARS the node
103
+ // (back to these defaults) on a mismatch: a new subscription is a clean
104
+ // slate. An unstamped node (written before the stamp existed) is read as
105
+ // belonging to the subscription it is found on, because nothing can prove
106
+ // otherwise and no live discount is ever taken away on a guess, and the
107
+ // pipeline stamps it there, so it clears on the next resubscribe like any
108
+ // other.
109
+ discount: {
110
+ valid: { type: 'boolean', default: false },
111
+ code: { type: 'string', default: null, nullable: true },
112
+ percent: { type: 'number', default: 0 },
113
+ amount: { type: 'number', default: 0 },
114
+ duration: { type: 'string', default: null, nullable: true },
115
+ source: { type: 'string', default: null, nullable: true },
116
+ resourceId: { type: 'string', default: null, nullable: true },
117
+ },
118
+ },
119
+ roles: {
120
+ $passthrough: true,
121
+ admin: { type: 'boolean', default: false },
122
+ betaTester: { type: 'boolean', default: false },
123
+ developer: { type: 'boolean', default: false },
124
+ },
125
+ flags: {
126
+ $passthrough: true,
127
+ signupProcessed: { type: 'boolean', default: false },
128
+ },
129
+ affiliate: {
130
+ code: { type: 'string', default: '$randomId' },
131
+ referrals: { type: 'array', default: [] },
132
+ },
133
+ metadata: {
134
+ created: '$timestamp:now',
135
+ updated: '$timestamp:now',
136
+ },
137
+ activity: {
138
+ geolocation: {
139
+ ip: { type: 'string', default: null, nullable: true },
140
+ continent: { type: 'string', default: null, nullable: true },
141
+ country: { type: 'string', default: null, nullable: true },
142
+ region: { type: 'string', default: null, nullable: true },
143
+ city: { type: 'string', default: null, nullable: true },
144
+ latitude: { type: 'number', default: 0 },
145
+ longitude: { type: 'number', default: 0 },
146
+ },
147
+ client: {
148
+ language: { type: 'string', default: null, nullable: true },
149
+ mobile: { type: 'boolean', default: false },
150
+ device: { type: 'string', default: null, nullable: true },
151
+ platform: { type: 'string', default: null, nullable: true },
152
+ browser: { type: 'string', default: null, nullable: true },
153
+ vendor: { type: 'string', default: null, nullable: true },
154
+ runtime: { type: 'string', default: null, nullable: true },
155
+ userAgent: { type: 'string', default: null, nullable: true },
156
+ url: { type: 'string', default: null, nullable: true },
157
+ },
158
+ },
159
+ api: {
160
+ clientId: { type: 'string', default: '$uuid' },
161
+ privateKey: { type: 'string', default: '$apiKey' },
162
+ },
163
+ // The documents this account owns, by KIND: `{ teams: ['team-abc'] }`
164
+ // ([#647](https://github.com/Omega-JS-Stack/omega/issues/647)). A counted
165
+ // feature's catalog entry names the kinds its counters mirror onto
166
+ // (`usage: { mirror: ['teams'] }`), and this is what resolves a kind to real
167
+ // document paths — so a mirror is declared once in config instead of
168
+ // re-derived at every call site. Server-written like `usage`: a client that
169
+ // could write it could point another account's counters at its own doc.
170
+ owns: {
171
+ $passthrough: true,
172
+ },
173
+ usage: {
174
+ $passthrough: true,
175
+ // Admin-granted extra credits, feature id → number
176
+ // ([#647](https://github.com/Omega-JS-Stack/omega/issues/647)). Declared
177
+ // HERE so the sibling `$template` never resolves it as a counter block:
178
+ // it is a map of limits, not a map of counts. `usage` is a framework field
179
+ // the security rules deny every client, so an override can only ever be
180
+ // server-written — which is what makes it trustworthy as a limit.
181
+ overrides: { $passthrough: true },
182
+ $template: {
183
+ monthly: { type: 'number', default: 0 },
184
+ daily: { type: 'number', default: 0 },
185
+ total: { type: 'number', default: 0 },
186
+ // When the counter last moved. The old `id` field went with the retired
187
+ // `increment(name, value, { id })` option (#647): nothing writes it now,
188
+ // and a schema field nothing fills reads as a fact that is always null.
189
+ last: {
190
+ timestamp: { type: 'string', default: '$oldDate' },
191
+ timestampUNIX: { type: 'number', default: 0 },
192
+ },
193
+ },
194
+ },
195
+ personal: {
196
+ birthday: '$timestamp',
197
+ gender: { type: 'string', default: null, nullable: true },
198
+ location: {
199
+ country: { type: 'string', default: null, nullable: true },
200
+ region: { type: 'string', default: null, nullable: true },
201
+ city: { type: 'string', default: null, nullable: true },
202
+ postalCode: { type: 'string', default: null, nullable: true },
203
+ street: { type: 'string', default: null, nullable: true },
204
+ },
205
+ name: {
206
+ first: { type: 'string', default: null, nullable: true },
207
+ last: { type: 'string', default: null, nullable: true },
208
+ },
209
+ company: {
210
+ name: { type: 'string', default: null, nullable: true },
211
+ position: { type: 'string', default: null, nullable: true },
212
+ },
213
+ telephone: {
214
+ countryCode: { type: 'number', default: 0 },
215
+ national: { type: 'number', default: 0 },
216
+ },
217
+ },
218
+ connections: {
219
+ $passthrough: true,
220
+ },
221
+ attribution: {
222
+ affiliate: {
223
+ code: { type: 'string', default: null, nullable: true },
224
+ timestamp: { type: 'string', default: null, nullable: true },
225
+ url: { type: 'string', default: null, nullable: true },
226
+ page: { type: 'string', default: null, nullable: true },
227
+ },
228
+ // The touch model: `first` is the visit that first brought the user here,
229
+ // written once and never overwritten; `last` is the newest TAGGED visit. No
230
+ // expiry — the timestamps carry any read-time lookback window. Replaces the
231
+ // single `utm` blob outright (no dual-read).
232
+ first: ATTRIBUTION_TOUCH,
233
+ last: ATTRIBUTION_TOUCH,
234
+ },
235
+ // The tracking-consent snapshot the client captured, stored verbatim: passthrough
236
+ // because this layer never interprets it — the consent module owns its shape. NOT
237
+ // the same thing as `consent` below, which is the legal/marketing decision.
238
+ trackingConsent: {
239
+ $passthrough: true,
240
+ },
241
+ consent: {
242
+ legal: {
243
+ status: { type: 'string', default: 'revoked' },
244
+ grantedAt: {
245
+ timestamp: { type: 'string', default: null, nullable: true },
246
+ timestampUNIX: { type: 'number', default: null, nullable: true },
247
+ source: { type: 'string', default: null, nullable: true },
248
+ ip: { type: 'string', default: null, nullable: true },
249
+ text: { type: 'string', default: null, nullable: true },
250
+ },
251
+ },
252
+ marketing: {
253
+ status: { type: 'string', default: 'revoked' },
254
+ grantedAt: {
255
+ timestamp: { type: 'string', default: null, nullable: true },
256
+ timestampUNIX: { type: 'number', default: null, nullable: true },
257
+ source: { type: 'string', default: null, nullable: true },
258
+ ip: { type: 'string', default: null, nullable: true },
259
+ text: { type: 'string', default: null, nullable: true },
260
+ },
261
+ revokedAt: {
262
+ timestamp: { type: 'string', default: null, nullable: true },
263
+ timestampUNIX: { type: 'number', default: null, nullable: true },
264
+ source: { type: 'string', default: null, nullable: true },
265
+ ip: { type: 'string', default: null, nullable: true },
266
+ text: { type: 'string', default: null, nullable: true },
267
+ },
268
+ },
269
+ },
270
+ };
271
+
272
+ module.exports = USER_SCHEMA;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * resolveSubscription — extracted verbatim from @omega.js/backend's User.resolveSubscription
3
+ * (the superset: @omega.js/client's drifted copy lacked `everPaid`).
4
+ *
5
+ * Resolves calculated subscription fields that require derivation logic.
6
+ * Raw data (product.id, status, trial, cancellation) is on the account directly.
7
+ * Returns: { plan, active, trialing, cancelling, everPaid }
8
+ * - plan: the plan ID the user effectively has access to RIGHT NOW ('basic' if cancelled/suspended)
9
+ * - active: user has active access (active, trialing, or cancelling)
10
+ * - trialing: user is in an active trial (status is 'active' but trial hasn't expired)
11
+ * - cancelling: cancellation is pending (status is 'active' but cancellation.pending is true)
12
+ * - everPaid: user has had a paid subscription at some point (payment.startDate exists)
13
+ */
14
+ function resolveSubscription(account) {
15
+ const subscription = (account?.subscription || account?.properties?.subscription) || {};
16
+ const productId = subscription.product?.id || 'basic';
17
+
18
+ let trialing = false;
19
+ let cancelling = false;
20
+
21
+ if (productId !== 'basic' && subscription.status === 'active') {
22
+ trialing = !!(subscription.trial?.claimed
23
+ && subscription.trial?.expires?.timestampUNIX > Math.floor(Date.now() / 1000));
24
+ cancelling = !trialing && !!subscription.cancellation?.pending;
25
+ }
26
+
27
+ const active = (productId !== 'basic' && subscription.status === 'active');
28
+
29
+ return {
30
+ plan: active ? productId : 'basic',
31
+ active,
32
+ trialing,
33
+ cancelling,
34
+ everPaid: (subscription.payment?.startDate?.timestampUNIX || 0) > 0,
35
+ };
36
+ }
37
+
38
+ module.exports = resolveSubscription;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The company layer's ONE discovery rule.
3
+ *
4
+ * A brand managed by a company workspace carries `.omega/company.json` at its
5
+ * root (stamped idempotently by company manage runs) pointing at the company
6
+ * root. Everything that cascades — the config chain (load.js), the .env chain
7
+ * (env.js), owner hooks (hooks.js) — resolves the company root through here,
8
+ * so the stamp is read exactly one way.
9
+ */
10
+
11
+ const fs = require('node:fs');
12
+ const path = require('node:path');
13
+
14
+ // A brand's pointer at its company root.
15
+ const COMPANY_MARKER = path.join('.omega', 'company.json');
16
+
17
+ /**
18
+ * The company root a brand points at via its .omega/company.json marker.
19
+ * @param {string} brandRoot
20
+ * @returns {string|null} Absolute company root, or null when unstamped/unreadable.
21
+ */
22
+ function readCompanyRoot(brandRoot) {
23
+ try {
24
+ const marker = JSON.parse(fs.readFileSync(path.join(brandRoot, COMPANY_MARKER), 'utf8'));
25
+ return typeof marker.root === 'string' && marker.root ? marker.root : null;
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ module.exports = { readCompanyRoot, COMPANY_MARKER };