@nxuss/lemma 1.43.0 → 1.44.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 (322) hide show
  1. package/README.md +1 -1
  2. package/bin/brain-ingest.js +18 -0
  3. package/bin/cloud.js +228 -0
  4. package/dist/cjs/cli/hostHooks.d.ts +6 -0
  5. package/dist/cjs/cli/hostHooks.d.ts.map +1 -1
  6. package/dist/cjs/cli/hostHooks.js +13 -3
  7. package/dist/cjs/cli/hostHooks.js.map +1 -1
  8. package/dist/cjs/cloud/CloudBrainClient.d.ts +52 -0
  9. package/dist/cjs/cloud/CloudBrainClient.d.ts.map +1 -0
  10. package/dist/cjs/cloud/CloudBrainClient.js +161 -0
  11. package/dist/cjs/cloud/CloudBrainClient.js.map +1 -0
  12. package/dist/cjs/cloud/CloudConfig.d.ts +41 -0
  13. package/dist/cjs/cloud/CloudConfig.d.ts.map +1 -0
  14. package/dist/cjs/cloud/CloudConfig.js +133 -0
  15. package/dist/cjs/cloud/CloudConfig.js.map +1 -0
  16. package/dist/cjs/cloud/CloudEntitlement.d.ts +55 -0
  17. package/dist/cjs/cloud/CloudEntitlement.d.ts.map +1 -0
  18. package/dist/cjs/cloud/CloudEntitlement.js +174 -0
  19. package/dist/cjs/cloud/CloudEntitlement.js.map +1 -0
  20. package/dist/cjs/cloud/billing/stripeApi.d.ts +43 -0
  21. package/dist/cjs/cloud/billing/stripeApi.d.ts.map +1 -0
  22. package/dist/cjs/cloud/billing/stripeApi.js +111 -0
  23. package/dist/cjs/cloud/billing/stripeApi.js.map +1 -0
  24. package/dist/cjs/cloud/billing/stripeWebhook.d.ts +35 -0
  25. package/dist/cjs/cloud/billing/stripeWebhook.d.ts.map +1 -0
  26. package/dist/cjs/cloud/billing/stripeWebhook.js +185 -0
  27. package/dist/cjs/cloud/billing/stripeWebhook.js.map +1 -0
  28. package/dist/cjs/cloud/console/ConsoleStore.d.ts +111 -0
  29. package/dist/cjs/cloud/console/ConsoleStore.d.ts.map +1 -0
  30. package/dist/cjs/cloud/console/ConsoleStore.js +172 -0
  31. package/dist/cjs/cloud/console/ConsoleStore.js.map +1 -0
  32. package/dist/cjs/cloud/console/consoleRouter.d.ts +68 -0
  33. package/dist/cjs/cloud/console/consoleRouter.d.ts.map +1 -0
  34. package/dist/cjs/cloud/console/consoleRouter.js +263 -0
  35. package/dist/cjs/cloud/console/consoleRouter.js.map +1 -0
  36. package/dist/cjs/cloud/console/mailer.d.ts +22 -0
  37. package/dist/cjs/cloud/console/mailer.d.ts.map +1 -0
  38. package/dist/cjs/cloud/console/mailer.js +35 -0
  39. package/dist/cjs/cloud/console/mailer.js.map +1 -0
  40. package/dist/cjs/cloud/identity/PlanPolicy.d.ts +16 -1
  41. package/dist/cjs/cloud/identity/PlanPolicy.d.ts.map +1 -1
  42. package/dist/cjs/cloud/identity/PlanPolicy.js +47 -7
  43. package/dist/cjs/cloud/identity/PlanPolicy.js.map +1 -1
  44. package/dist/cjs/cloud/identity/RateLimiter.d.ts +21 -1
  45. package/dist/cjs/cloud/identity/RateLimiter.d.ts.map +1 -1
  46. package/dist/cjs/cloud/identity/RateLimiter.js +59 -2
  47. package/dist/cjs/cloud/identity/RateLimiter.js.map +1 -1
  48. package/dist/cjs/cloud/identity/TenantResolver.d.ts +4 -1
  49. package/dist/cjs/cloud/identity/TenantResolver.d.ts.map +1 -1
  50. package/dist/cjs/cloud/identity/TenantResolver.js +1 -1
  51. package/dist/cjs/cloud/identity/TenantResolver.js.map +1 -1
  52. package/dist/cjs/cloud/identity/authenticateV2.d.ts.map +1 -1
  53. package/dist/cjs/cloud/identity/authenticateV2.js +7 -4
  54. package/dist/cjs/cloud/identity/authenticateV2.js.map +1 -1
  55. package/dist/cjs/cloud/identity/identityStore.d.ts +85 -10
  56. package/dist/cjs/cloud/identity/identityStore.d.ts.map +1 -1
  57. package/dist/cjs/cloud/identity/identityStore.js +184 -2
  58. package/dist/cjs/cloud/identity/identityStore.js.map +1 -1
  59. package/dist/cjs/cloud/metering/PostgresLedgerStore.d.ts +16 -0
  60. package/dist/cjs/cloud/metering/PostgresLedgerStore.d.ts.map +1 -0
  61. package/dist/cjs/cloud/metering/PostgresLedgerStore.js +44 -0
  62. package/dist/cjs/cloud/metering/PostgresLedgerStore.js.map +1 -0
  63. package/dist/cjs/cloud/metering/UsageLedger.d.ts +37 -0
  64. package/dist/cjs/cloud/metering/UsageLedger.d.ts.map +1 -1
  65. package/dist/cjs/cloud/metering/UsageLedger.js +80 -17
  66. package/dist/cjs/cloud/metering/UsageLedger.js.map +1 -1
  67. package/dist/cjs/cloud/metering/index.d.ts +1 -0
  68. package/dist/cjs/cloud/metering/index.d.ts.map +1 -1
  69. package/dist/cjs/cloud/metering/index.js +1 -0
  70. package/dist/cjs/cloud/metering/index.js.map +1 -1
  71. package/dist/cjs/cloud/store/FileBrainStore.d.ts +1 -0
  72. package/dist/cjs/cloud/store/FileBrainStore.d.ts.map +1 -1
  73. package/dist/cjs/cloud/store/FileBrainStore.js +3 -0
  74. package/dist/cjs/cloud/store/FileBrainStore.js.map +1 -1
  75. package/dist/cjs/cloud/store/PostgresBrainStore.d.ts +1 -0
  76. package/dist/cjs/cloud/store/PostgresBrainStore.d.ts.map +1 -1
  77. package/dist/cjs/cloud/store/PostgresBrainStore.js +4 -0
  78. package/dist/cjs/cloud/store/PostgresBrainStore.js.map +1 -1
  79. package/dist/cjs/cloud/v2/app.d.ts.map +1 -1
  80. package/dist/cjs/cloud/v2/app.js +6 -0
  81. package/dist/cjs/cloud/v2/app.js.map +1 -1
  82. package/dist/cjs/cloud/v2/inputGuard.d.ts +23 -0
  83. package/dist/cjs/cloud/v2/inputGuard.d.ts.map +1 -0
  84. package/dist/cjs/cloud/v2/inputGuard.js +71 -0
  85. package/dist/cjs/cloud/v2/inputGuard.js.map +1 -0
  86. package/dist/cjs/cloud/v2/routes/admin.d.ts +24 -0
  87. package/dist/cjs/cloud/v2/routes/admin.d.ts.map +1 -0
  88. package/dist/cjs/cloud/v2/routes/admin.js +329 -0
  89. package/dist/cjs/cloud/v2/routes/admin.js.map +1 -0
  90. package/dist/cjs/cloud/v2/routes/entitlement.d.ts +13 -0
  91. package/dist/cjs/cloud/v2/routes/entitlement.d.ts.map +1 -0
  92. package/dist/cjs/cloud/v2/routes/entitlement.js +24 -0
  93. package/dist/cjs/cloud/v2/routes/entitlement.js.map +1 -0
  94. package/dist/cjs/cloud/v2/routes/index.d.ts +14 -1
  95. package/dist/cjs/cloud/v2/routes/index.d.ts.map +1 -1
  96. package/dist/cjs/cloud/v2/routes/index.js +36 -0
  97. package/dist/cjs/cloud/v2/routes/index.js.map +1 -1
  98. package/dist/cjs/cloud/v2/routes/memories.d.ts +21 -2
  99. package/dist/cjs/cloud/v2/routes/memories.d.ts.map +1 -1
  100. package/dist/cjs/cloud/v2/routes/memories.js +77 -0
  101. package/dist/cjs/cloud/v2/routes/memories.js.map +1 -1
  102. package/dist/cjs/cloud/v2/routes/recall.d.ts +1 -0
  103. package/dist/cjs/cloud/v2/routes/recall.d.ts.map +1 -1
  104. package/dist/cjs/cloud/v2/routes/recall.js +4 -0
  105. package/dist/cjs/cloud/v2/routes/recall.js.map +1 -1
  106. package/dist/cjs/cloud/v2/routes/tenant.d.ts +35 -0
  107. package/dist/cjs/cloud/v2/routes/tenant.d.ts.map +1 -0
  108. package/dist/cjs/cloud/v2/routes/tenant.js +62 -0
  109. package/dist/cjs/cloud/v2/routes/tenant.js.map +1 -0
  110. package/dist/cjs/cloud/v2/routes/usage.d.ts +1 -1
  111. package/dist/cjs/cloud/v2/routes/usage.d.ts.map +1 -1
  112. package/dist/cjs/cloud/v2/routes/verify.d.ts +1 -0
  113. package/dist/cjs/cloud/v2/routes/verify.d.ts.map +1 -1
  114. package/dist/cjs/cloud/v2/routes/verify.js +4 -0
  115. package/dist/cjs/cloud/v2/routes/verify.js.map +1 -1
  116. package/dist/cjs/cloud/v2/server.d.ts +9 -3
  117. package/dist/cjs/cloud/v2/server.d.ts.map +1 -1
  118. package/dist/cjs/cloud/v2/server.js +36 -2
  119. package/dist/cjs/cloud/v2/server.js.map +1 -1
  120. package/dist/cjs/cloud/v2/usageRecorder.d.ts +19 -0
  121. package/dist/cjs/cloud/v2/usageRecorder.d.ts.map +1 -0
  122. package/dist/cjs/cloud/v2/usageRecorder.js +42 -0
  123. package/dist/cjs/cloud/v2/usageRecorder.js.map +1 -0
  124. package/dist/cjs/contracts/api-v2.types.d.ts +90 -2
  125. package/dist/cjs/contracts/api-v2.types.d.ts.map +1 -1
  126. package/dist/cjs/contracts/store.d.ts +2 -0
  127. package/dist/cjs/contracts/store.d.ts.map +1 -1
  128. package/dist/cjs/mcp/index.js +3 -0
  129. package/dist/cjs/mcp/index.js.map +1 -1
  130. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  131. package/dist/cjs/mcp/tools/memory.js +74 -4
  132. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  133. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  134. package/dist/cjs/mcp/tools.js.map +1 -1
  135. package/dist/cjs/proxy/KeyManager.d.ts.map +1 -1
  136. package/dist/cjs/proxy/KeyManager.js +5 -0
  137. package/dist/cjs/proxy/KeyManager.js.map +1 -1
  138. package/dist/cjs/subconscious/CloudBrain.d.ts +77 -0
  139. package/dist/cjs/subconscious/CloudBrain.d.ts.map +1 -0
  140. package/dist/cjs/subconscious/CloudBrain.js +347 -0
  141. package/dist/cjs/subconscious/CloudBrain.js.map +1 -0
  142. package/dist/cjs/subconscious/ProjectIdentity.d.ts +9 -0
  143. package/dist/cjs/subconscious/ProjectIdentity.d.ts.map +1 -0
  144. package/dist/cjs/subconscious/ProjectIdentity.js +63 -0
  145. package/dist/cjs/subconscious/ProjectIdentity.js.map +1 -0
  146. package/dist/cjs/subconscious/TeamBrain.d.ts +9 -3
  147. package/dist/cjs/subconscious/TeamBrain.d.ts.map +1 -1
  148. package/dist/cjs/subconscious/TeamBrain.js +39 -5
  149. package/dist/cjs/subconscious/TeamBrain.js.map +1 -1
  150. package/dist/cjs/utils/ProLicense.d.ts.map +1 -1
  151. package/dist/cjs/utils/ProLicense.js +11 -3
  152. package/dist/cjs/utils/ProLicense.js.map +1 -1
  153. package/dist/cjs/utils/SessionCapture.d.ts +2 -0
  154. package/dist/cjs/utils/SessionCapture.d.ts.map +1 -1
  155. package/dist/cjs/utils/SessionCapture.js +5 -0
  156. package/dist/cjs/utils/SessionCapture.js.map +1 -1
  157. package/dist/cjs/utils/StopNudge.d.ts +8 -0
  158. package/dist/cjs/utils/StopNudge.d.ts.map +1 -0
  159. package/dist/cjs/utils/StopNudge.js +93 -0
  160. package/dist/cjs/utils/StopNudge.js.map +1 -0
  161. package/dist/esm/cli/hostHooks.d.ts +6 -0
  162. package/dist/esm/cli/hostHooks.d.ts.map +1 -1
  163. package/dist/esm/cli/hostHooks.js +12 -2
  164. package/dist/esm/cli/hostHooks.js.map +1 -1
  165. package/dist/esm/cloud/CloudBrainClient.d.ts +52 -0
  166. package/dist/esm/cloud/CloudBrainClient.d.ts.map +1 -0
  167. package/dist/esm/cloud/CloudBrainClient.js +153 -0
  168. package/dist/esm/cloud/CloudBrainClient.js.map +1 -0
  169. package/dist/esm/cloud/CloudConfig.d.ts +41 -0
  170. package/dist/esm/cloud/CloudConfig.d.ts.map +1 -0
  171. package/dist/esm/cloud/CloudConfig.js +118 -0
  172. package/dist/esm/cloud/CloudConfig.js.map +1 -0
  173. package/dist/esm/cloud/CloudEntitlement.d.ts +55 -0
  174. package/dist/esm/cloud/CloudEntitlement.d.ts.map +1 -0
  175. package/dist/esm/cloud/CloudEntitlement.js +159 -0
  176. package/dist/esm/cloud/CloudEntitlement.js.map +1 -0
  177. package/dist/esm/cloud/billing/stripeApi.d.ts +43 -0
  178. package/dist/esm/cloud/billing/stripeApi.d.ts.map +1 -0
  179. package/dist/esm/cloud/billing/stripeApi.js +103 -0
  180. package/dist/esm/cloud/billing/stripeApi.js.map +1 -0
  181. package/dist/esm/cloud/billing/stripeWebhook.d.ts +35 -0
  182. package/dist/esm/cloud/billing/stripeWebhook.d.ts.map +1 -0
  183. package/dist/esm/cloud/billing/stripeWebhook.js +176 -0
  184. package/dist/esm/cloud/billing/stripeWebhook.js.map +1 -0
  185. package/dist/esm/cloud/console/ConsoleStore.d.ts +111 -0
  186. package/dist/esm/cloud/console/ConsoleStore.d.ts.map +1 -0
  187. package/dist/esm/cloud/console/ConsoleStore.js +161 -0
  188. package/dist/esm/cloud/console/ConsoleStore.js.map +1 -0
  189. package/dist/esm/cloud/console/consoleRouter.d.ts +68 -0
  190. package/dist/esm/cloud/console/consoleRouter.d.ts.map +1 -0
  191. package/dist/esm/cloud/console/consoleRouter.js +252 -0
  192. package/dist/esm/cloud/console/consoleRouter.js.map +1 -0
  193. package/dist/esm/cloud/console/mailer.d.ts +22 -0
  194. package/dist/esm/cloud/console/mailer.d.ts.map +1 -0
  195. package/dist/esm/cloud/console/mailer.js +30 -0
  196. package/dist/esm/cloud/console/mailer.js.map +1 -0
  197. package/dist/esm/cloud/identity/PlanPolicy.d.ts +16 -1
  198. package/dist/esm/cloud/identity/PlanPolicy.d.ts.map +1 -1
  199. package/dist/esm/cloud/identity/PlanPolicy.js +46 -6
  200. package/dist/esm/cloud/identity/PlanPolicy.js.map +1 -1
  201. package/dist/esm/cloud/identity/RateLimiter.d.ts +21 -1
  202. package/dist/esm/cloud/identity/RateLimiter.d.ts.map +1 -1
  203. package/dist/esm/cloud/identity/RateLimiter.js +57 -2
  204. package/dist/esm/cloud/identity/RateLimiter.js.map +1 -1
  205. package/dist/esm/cloud/identity/TenantResolver.d.ts +4 -1
  206. package/dist/esm/cloud/identity/TenantResolver.d.ts.map +1 -1
  207. package/dist/esm/cloud/identity/TenantResolver.js +1 -1
  208. package/dist/esm/cloud/identity/TenantResolver.js.map +1 -1
  209. package/dist/esm/cloud/identity/authenticateV2.d.ts.map +1 -1
  210. package/dist/esm/cloud/identity/authenticateV2.js +7 -4
  211. package/dist/esm/cloud/identity/authenticateV2.js.map +1 -1
  212. package/dist/esm/cloud/identity/identityStore.d.ts +85 -10
  213. package/dist/esm/cloud/identity/identityStore.d.ts.map +1 -1
  214. package/dist/esm/cloud/identity/identityStore.js +180 -1
  215. package/dist/esm/cloud/identity/identityStore.js.map +1 -1
  216. package/dist/esm/cloud/metering/PostgresLedgerStore.d.ts +16 -0
  217. package/dist/esm/cloud/metering/PostgresLedgerStore.d.ts.map +1 -0
  218. package/dist/esm/cloud/metering/PostgresLedgerStore.js +40 -0
  219. package/dist/esm/cloud/metering/PostgresLedgerStore.js.map +1 -0
  220. package/dist/esm/cloud/metering/UsageLedger.d.ts +37 -0
  221. package/dist/esm/cloud/metering/UsageLedger.d.ts.map +1 -1
  222. package/dist/esm/cloud/metering/UsageLedger.js +78 -16
  223. package/dist/esm/cloud/metering/UsageLedger.js.map +1 -1
  224. package/dist/esm/cloud/metering/index.d.ts +1 -0
  225. package/dist/esm/cloud/metering/index.d.ts.map +1 -1
  226. package/dist/esm/cloud/metering/index.js +1 -0
  227. package/dist/esm/cloud/metering/index.js.map +1 -1
  228. package/dist/esm/cloud/store/FileBrainStore.d.ts +1 -0
  229. package/dist/esm/cloud/store/FileBrainStore.d.ts.map +1 -1
  230. package/dist/esm/cloud/store/FileBrainStore.js +3 -0
  231. package/dist/esm/cloud/store/FileBrainStore.js.map +1 -1
  232. package/dist/esm/cloud/store/PostgresBrainStore.d.ts +1 -0
  233. package/dist/esm/cloud/store/PostgresBrainStore.d.ts.map +1 -1
  234. package/dist/esm/cloud/store/PostgresBrainStore.js +4 -0
  235. package/dist/esm/cloud/store/PostgresBrainStore.js.map +1 -1
  236. package/dist/esm/cloud/v2/app.d.ts.map +1 -1
  237. package/dist/esm/cloud/v2/app.js +6 -0
  238. package/dist/esm/cloud/v2/app.js.map +1 -1
  239. package/dist/esm/cloud/v2/inputGuard.d.ts +23 -0
  240. package/dist/esm/cloud/v2/inputGuard.d.ts.map +1 -0
  241. package/dist/esm/cloud/v2/inputGuard.js +63 -0
  242. package/dist/esm/cloud/v2/inputGuard.js.map +1 -0
  243. package/dist/esm/cloud/v2/routes/admin.d.ts +24 -0
  244. package/dist/esm/cloud/v2/routes/admin.d.ts.map +1 -0
  245. package/dist/esm/cloud/v2/routes/admin.js +322 -0
  246. package/dist/esm/cloud/v2/routes/admin.js.map +1 -0
  247. package/dist/esm/cloud/v2/routes/entitlement.d.ts +13 -0
  248. package/dist/esm/cloud/v2/routes/entitlement.d.ts.map +1 -0
  249. package/dist/esm/cloud/v2/routes/entitlement.js +21 -0
  250. package/dist/esm/cloud/v2/routes/entitlement.js.map +1 -0
  251. package/dist/esm/cloud/v2/routes/index.d.ts +14 -1
  252. package/dist/esm/cloud/v2/routes/index.d.ts.map +1 -1
  253. package/dist/esm/cloud/v2/routes/index.js +37 -1
  254. package/dist/esm/cloud/v2/routes/index.js.map +1 -1
  255. package/dist/esm/cloud/v2/routes/memories.d.ts +21 -2
  256. package/dist/esm/cloud/v2/routes/memories.d.ts.map +1 -1
  257. package/dist/esm/cloud/v2/routes/memories.js +75 -0
  258. package/dist/esm/cloud/v2/routes/memories.js.map +1 -1
  259. package/dist/esm/cloud/v2/routes/recall.d.ts +1 -0
  260. package/dist/esm/cloud/v2/routes/recall.d.ts.map +1 -1
  261. package/dist/esm/cloud/v2/routes/recall.js +5 -1
  262. package/dist/esm/cloud/v2/routes/recall.js.map +1 -1
  263. package/dist/esm/cloud/v2/routes/tenant.d.ts +35 -0
  264. package/dist/esm/cloud/v2/routes/tenant.d.ts.map +1 -0
  265. package/dist/esm/cloud/v2/routes/tenant.js +58 -0
  266. package/dist/esm/cloud/v2/routes/tenant.js.map +1 -0
  267. package/dist/esm/cloud/v2/routes/usage.d.ts +1 -1
  268. package/dist/esm/cloud/v2/routes/usage.d.ts.map +1 -1
  269. package/dist/esm/cloud/v2/routes/verify.d.ts +1 -0
  270. package/dist/esm/cloud/v2/routes/verify.d.ts.map +1 -1
  271. package/dist/esm/cloud/v2/routes/verify.js +5 -1
  272. package/dist/esm/cloud/v2/routes/verify.js.map +1 -1
  273. package/dist/esm/cloud/v2/server.d.ts +9 -3
  274. package/dist/esm/cloud/v2/server.d.ts.map +1 -1
  275. package/dist/esm/cloud/v2/server.js +36 -3
  276. package/dist/esm/cloud/v2/server.js.map +1 -1
  277. package/dist/esm/cloud/v2/usageRecorder.d.ts +19 -0
  278. package/dist/esm/cloud/v2/usageRecorder.d.ts.map +1 -0
  279. package/dist/esm/cloud/v2/usageRecorder.js +37 -0
  280. package/dist/esm/cloud/v2/usageRecorder.js.map +1 -0
  281. package/dist/esm/contracts/api-v2.types.d.ts +90 -2
  282. package/dist/esm/contracts/api-v2.types.d.ts.map +1 -1
  283. package/dist/esm/contracts/store.d.ts +2 -0
  284. package/dist/esm/contracts/store.d.ts.map +1 -1
  285. package/dist/esm/mcp/index.js +3 -0
  286. package/dist/esm/mcp/index.js.map +1 -1
  287. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  288. package/dist/esm/mcp/tools/memory.js +74 -4
  289. package/dist/esm/mcp/tools/memory.js.map +1 -1
  290. package/dist/esm/mcp/tools.d.ts.map +1 -1
  291. package/dist/esm/mcp/tools.js.map +1 -1
  292. package/dist/esm/proxy/KeyManager.d.ts.map +1 -1
  293. package/dist/esm/proxy/KeyManager.js +5 -0
  294. package/dist/esm/proxy/KeyManager.js.map +1 -1
  295. package/dist/esm/subconscious/CloudBrain.d.ts +77 -0
  296. package/dist/esm/subconscious/CloudBrain.d.ts.map +1 -0
  297. package/dist/esm/subconscious/CloudBrain.js +330 -0
  298. package/dist/esm/subconscious/CloudBrain.js.map +1 -0
  299. package/dist/esm/subconscious/ProjectIdentity.d.ts +9 -0
  300. package/dist/esm/subconscious/ProjectIdentity.d.ts.map +1 -0
  301. package/dist/esm/subconscious/ProjectIdentity.js +56 -0
  302. package/dist/esm/subconscious/ProjectIdentity.js.map +1 -0
  303. package/dist/esm/subconscious/TeamBrain.d.ts +9 -3
  304. package/dist/esm/subconscious/TeamBrain.d.ts.map +1 -1
  305. package/dist/esm/subconscious/TeamBrain.js +39 -7
  306. package/dist/esm/subconscious/TeamBrain.js.map +1 -1
  307. package/dist/esm/utils/ProLicense.d.ts.map +1 -1
  308. package/dist/esm/utils/ProLicense.js +11 -3
  309. package/dist/esm/utils/ProLicense.js.map +1 -1
  310. package/dist/esm/utils/SessionCapture.d.ts +2 -0
  311. package/dist/esm/utils/SessionCapture.d.ts.map +1 -1
  312. package/dist/esm/utils/SessionCapture.js +5 -0
  313. package/dist/esm/utils/SessionCapture.js.map +1 -1
  314. package/dist/esm/utils/StopNudge.d.ts +8 -0
  315. package/dist/esm/utils/StopNudge.d.ts.map +1 -0
  316. package/dist/esm/utils/StopNudge.js +86 -0
  317. package/dist/esm/utils/StopNudge.js.map +1 -0
  318. package/lemma-proxy.cjs +5 -0
  319. package/package.json +2 -1
  320. package/sdks/crewai/dist/ts/src/client.d.ts +5 -1
  321. package/sdks/crewai/dist/ts/src/client.js +8 -0
  322. package/sdks/crewai/dist/ts/src/types.d.ts +32 -1
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Lemma Cloud console — members, one-time login links and sessions.
3
+ *
4
+ * Members live in `tenant_seats`. An active email belongs to one tenant only (the login form takes
5
+ * an email and nothing else). Tokens are random and stored as sha256 hashes, never in the clear.
6
+ * A session does not carry the role: `findSession` joins the member row, so a removed member or a
7
+ * changed role is felt on the very next request.
8
+ *
9
+ * `InMemoryConsoleStore` serves tests and the no-database dev path; `PostgresConsoleStore` is production.
10
+ */
11
+ import crypto from 'crypto';
12
+ export const MEMBER_ROLES = ['owner', 'admin', 'member'];
13
+ export const normalizeEmail = (email) => email.trim().toLowerCase();
14
+ export const hashToken = (token) => crypto.createHash('sha256').update(token).digest('hex');
15
+ /** 256 bits, URL-safe. Only its hash is ever stored. */
16
+ export const newToken = () => crypto.randomBytes(32).toString('base64url');
17
+ const newMemberId = () => `mem_${crypto.randomBytes(6).toString('hex')}`;
18
+ export class InMemoryConsoleStore {
19
+ constructor(identity) {
20
+ this.identity = identity;
21
+ this.members = [];
22
+ this.loginTokens = new Map();
23
+ this.sessions = new Map();
24
+ }
25
+ async addMember(tenantId, rawEmail, role) {
26
+ const email = normalizeEmail(rawEmail);
27
+ if (!(await this.identity.getTenant(tenantId)))
28
+ return { ok: false, reason: 'no_tenant' };
29
+ const active = this.members.find((m) => !m.removed && m.email === email);
30
+ if (active)
31
+ return { ok: false, reason: active.tenantId === tenantId ? 'exists' : 'other_tenant' };
32
+ const row = { id: newMemberId(), tenantId, email, role, createdAt: Date.now(), removed: false };
33
+ this.members.push(row);
34
+ return { ok: true, member: toMember(row) };
35
+ }
36
+ async listMembers(tenantId) {
37
+ return this.members.filter((m) => !m.removed && m.tenantId === tenantId).map(toMember);
38
+ }
39
+ async removeMember(tenantId, rawEmail) {
40
+ const email = normalizeEmail(rawEmail);
41
+ const row = this.members.find((m) => !m.removed && m.tenantId === tenantId && m.email === email);
42
+ if (!row)
43
+ return false;
44
+ row.removed = true;
45
+ for (const [hash, s] of this.sessions)
46
+ if (s.tenantId === tenantId && s.email === email)
47
+ this.sessions.delete(hash);
48
+ return true;
49
+ }
50
+ async findMemberByEmail(rawEmail) {
51
+ const email = normalizeEmail(rawEmail);
52
+ const row = this.members.find((m) => !m.removed && m.email === email);
53
+ return row ? toMember(row) : null;
54
+ }
55
+ async createLoginToken(i) {
56
+ this.loginTokens.set(i.tokenHash, { tenantId: i.tenantId, email: normalizeEmail(i.email), expiresAt: i.expiresAt, used: false });
57
+ }
58
+ async consumeLoginToken(tokenHash, now) {
59
+ const t = this.loginTokens.get(tokenHash);
60
+ if (!t || t.used || t.expiresAt <= now)
61
+ return null;
62
+ t.used = true; // synchronous between the check and the write: atomic on one event loop
63
+ return { tenantId: t.tenantId, email: t.email };
64
+ }
65
+ async createSession(i) {
66
+ this.sessions.set(i.tokenHash, { tenantId: i.tenantId, email: normalizeEmail(i.email), expiresAt: i.expiresAt });
67
+ }
68
+ async findSession(tokenHash, now) {
69
+ const s = this.sessions.get(tokenHash);
70
+ if (!s || s.expiresAt <= now)
71
+ return null;
72
+ const member = this.members.find((m) => !m.removed && m.tenantId === s.tenantId && m.email === s.email);
73
+ return member ? { tenantId: s.tenantId, email: s.email, role: member.role } : null;
74
+ }
75
+ async deleteSession(tokenHash) {
76
+ this.sessions.delete(tokenHash);
77
+ }
78
+ }
79
+ const toMember = (r) => ({ id: r.id, tenantId: r.tenantId, email: r.email, role: r.role, createdAt: r.createdAt });
80
+ export class PostgresConsoleStore {
81
+ constructor(pool) {
82
+ this.pool = pool;
83
+ }
84
+ async addMember(tenantId, rawEmail, role) {
85
+ const email = normalizeEmail(rawEmail);
86
+ const existing = await this.findMemberByEmail(email);
87
+ if (existing)
88
+ return { ok: false, reason: existing.tenantId === tenantId ? 'exists' : 'other_tenant' };
89
+ const id = newMemberId();
90
+ try {
91
+ // A removed member of this tenant is brought back instead of colliding with UNIQUE (tenant_id, email).
92
+ const { rows } = await this.pool.query(`INSERT INTO tenant_seats (id, tenant_id, email, role) VALUES ($1, $2, $3, $4)
93
+ ON CONFLICT (tenant_id, email) DO UPDATE SET removed = FALSE, role = EXCLUDED.role
94
+ RETURNING id, tenant_id, email, role, created_at`, [id, tenantId, email, role]);
95
+ return { ok: true, member: rowToMember(rows[0]) };
96
+ }
97
+ catch (err) {
98
+ if (err?.code === '23503')
99
+ return { ok: false, reason: 'no_tenant' };
100
+ if (err?.code === '23505') {
101
+ // Lost a race with another add of the same email.
102
+ const now = await this.findMemberByEmail(email);
103
+ return { ok: false, reason: now && now.tenantId === tenantId ? 'exists' : 'other_tenant' };
104
+ }
105
+ throw err;
106
+ }
107
+ }
108
+ async listMembers(tenantId) {
109
+ const { rows } = await this.pool.query('SELECT id, tenant_id, email, role, created_at FROM tenant_seats WHERE tenant_id = $1 AND NOT removed ORDER BY created_at, email', [tenantId]);
110
+ return rows.map(rowToMember);
111
+ }
112
+ async removeMember(tenantId, rawEmail) {
113
+ const email = normalizeEmail(rawEmail);
114
+ const { rowCount } = await this.pool.query('UPDATE tenant_seats SET removed = TRUE WHERE tenant_id = $1 AND lower(email) = $2 AND NOT removed', [tenantId, email]);
115
+ await this.pool.query('DELETE FROM console_sessions WHERE tenant_id = $1 AND lower(email) = $2', [tenantId, email]);
116
+ return (rowCount ?? 0) > 0;
117
+ }
118
+ async findMemberByEmail(rawEmail) {
119
+ const { rows } = await this.pool.query('SELECT id, tenant_id, email, role, created_at FROM tenant_seats WHERE lower(email) = $1 AND NOT removed LIMIT 1', [normalizeEmail(rawEmail)]);
120
+ return rows.length ? rowToMember(rows[0]) : null;
121
+ }
122
+ async createLoginToken(i) {
123
+ await this.pool.query('INSERT INTO console_login_tokens (token_hash, tenant_id, email, expires_at) VALUES ($1, $2, $3, $4)', [
124
+ i.tokenHash,
125
+ i.tenantId,
126
+ normalizeEmail(i.email),
127
+ new Date(i.expiresAt),
128
+ ]);
129
+ }
130
+ async consumeLoginToken(tokenHash, now) {
131
+ // One statement: only the first caller flips used_at, so a link works once even under a race.
132
+ const { rows } = await this.pool.query(`UPDATE console_login_tokens SET used_at = now()
133
+ WHERE token_hash = $1 AND used_at IS NULL AND expires_at > $2
134
+ RETURNING tenant_id, email`, [tokenHash, new Date(now)]);
135
+ // Housekeeping on the way: expired rows are of no use to anyone.
136
+ this.pool.query('DELETE FROM console_login_tokens WHERE expires_at < $1', [new Date(now - 24 * 3600 * 1000)]).catch(() => undefined);
137
+ return rows.length ? { tenantId: rows[0].tenant_id, email: rows[0].email } : null;
138
+ }
139
+ async createSession(i) {
140
+ await this.pool.query('INSERT INTO console_sessions (token_hash, tenant_id, email, expires_at) VALUES ($1, $2, $3, $4)', [
141
+ i.tokenHash,
142
+ i.tenantId,
143
+ normalizeEmail(i.email),
144
+ new Date(i.expiresAt),
145
+ ]);
146
+ }
147
+ async findSession(tokenHash, now) {
148
+ const { rows } = await this.pool.query(`SELECT s.tenant_id, s.email, m.role
149
+ FROM console_sessions s
150
+ JOIN tenant_seats m ON m.tenant_id = s.tenant_id AND lower(m.email) = s.email AND NOT m.removed
151
+ WHERE s.token_hash = $1 AND s.expires_at > $2`, [tokenHash, new Date(now)]);
152
+ return rows.length ? { tenantId: rows[0].tenant_id, email: rows[0].email, role: rows[0].role } : null;
153
+ }
154
+ async deleteSession(tokenHash) {
155
+ await this.pool.query('DELETE FROM console_sessions WHERE token_hash = $1', [tokenHash]);
156
+ }
157
+ }
158
+ function rowToMember(r) {
159
+ return { id: r.id, tenantId: r.tenant_id, email: r.email, role: r.role, createdAt: new Date(r.created_at).getTime() };
160
+ }
161
+ //# sourceMappingURL=ConsoleStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsoleStore.js","sourceRoot":"","sources":["../../../../src/cloud/console/ConsoleStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAI5B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAuClE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5G,wDAAwD;AACxD,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACnF,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AAMjF,MAAM,OAAO,oBAAoB;IAK/B,YAA6B,QAA0C;QAA1C,aAAQ,GAAR,QAAQ,CAAkC;QAJtD,YAAO,GAAgB,EAAE,CAAC;QAC1B,gBAAW,GAAG,IAAI,GAAG,EAAiF,CAAC;QACvG,aAAQ,GAAG,IAAI,GAAG,EAAkE,CAAC;IAE5B,CAAC;IAE3E,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,QAAgB,EAAE,IAAgB;QAClE,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAC1F,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QACzE,IAAI,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;QACnG,MAAM,GAAG,GAAc,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC3G,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,QAAgB;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzF,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,QAAgB;QACnD,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QACjG,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;QACnB,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK;gBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAAgB;QACtC,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QACtE,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,CAA4E;QACjG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnI,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,SAAiB,EAAE,GAAW;QACpD,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG;YAAE,OAAO,IAAI,CAAC;QACpD,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,wEAAwE;QACvF,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,CAA4E;QAC9F,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;IACnH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,GAAW;QAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;QACxG,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACrF,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;CACF;AAED,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;AAEnI,MAAM,OAAO,oBAAoB;IAC/B,YAA6B,IAAU;QAAV,SAAI,GAAJ,IAAI,CAAM;IAAG,CAAC;IAE3C,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,QAAgB,EAAE,IAAgB;QAClE,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;QACvG,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,uGAAuG;YACvG,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACpC;;0DAEkD,EAClD,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,CAC5B,CAAC;YACF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,EAAE,IAAI,KAAK,OAAO;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;YACrE,IAAI,GAAG,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC1B,kDAAkD;gBAClD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;YAC7F,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,QAAgB;QAChC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACpC,iIAAiI,EACjI,CAAC,QAAQ,CAAC,CACX,CAAC;QACF,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,QAAgB;QACnD,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mGAAmG,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;QACnK,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,yEAAyE,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;QACpH,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAAgB;QACtC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACpC,iHAAiH,EACjH,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAC3B,CAAC;QACF,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,CAA4E;QACjG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,qGAAqG,EAAE;YAC3H,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,QAAQ;YACV,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;YACvB,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;SACtB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,SAAiB,EAAE,GAAW;QACpD,8FAA8F;QAC9F,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACpC;;mCAE6B,EAC7B,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAC3B,CAAC;QACF,iEAAiE;QACjE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,wDAAwD,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACrI,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpF,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,CAA4E;QAC9F,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,iGAAiG,EAAE;YACvH,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,QAAQ;YACV,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;YACvB,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;SACtB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,GAAW;QAC9C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACpC;;;sDAGgD,EAChD,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAC3B,CAAC;QACF,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACtH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,oDAAoD,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3F,CAAC;CACF;AAED,SAAS,WAAW,CAAC,CAAsB;IACzC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAkB,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;AACtI,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Lemma Cloud console — the web app's server side, mounted at /console.
3
+ *
4
+ * GET /console/ the static app (console/index.html, app.js, styles.css)
5
+ * POST /console/api/login {email} asks for a sign-in link: ALWAYS 202, so it cannot tell who is a member
6
+ * POST /console/api/verify {token} spends the link, starts a session (HttpOnly cookie)
7
+ * POST /console/api/logout
8
+ * GET /console/api/me who you are, your tenant's plan, limits, use and (owner/admin) billing
9
+ * GET /console/api/usage owner/admin: requests and tokens by operation and by dev, this month
10
+ * GET /console/api/team owner/admin: members, keys (never a secret), seats
11
+ * POST /console/api/billing/portal owner/admin: Stripe billing-portal link
12
+ *
13
+ * It is a separate identity from the API keys on purpose: a key belongs to a machine and a tenant, a
14
+ * session belongs to a person. Sessions live in the database, so removing a member ends their access at once.
15
+ *
16
+ * Defences, each cheap: the link travels in the URL FRAGMENT (never reaches a server log or a Referer) and is
17
+ * posted by the page; the cookie is HttpOnly + Secure + SameSite=Lax and scoped to /console; every POST needs
18
+ * a custom header and a same-origin Origin (so a cross-site form cannot act); the CSP allows only our own files.
19
+ */
20
+ import { type Request, type Router } from 'express';
21
+ import type { BrainStore } from '../../contracts/store.js';
22
+ import type { IdentityStore } from '../identity/identityStore.js';
23
+ import type { PlanPolicy } from '../identity/PlanPolicy.js';
24
+ import type { RateLimiter } from '../identity/RateLimiter.js';
25
+ import type { UsageLedger } from '../metering/index.js';
26
+ import type { StripeApi } from '../billing/stripeApi.js';
27
+ import { type ConsoleStore } from './ConsoleStore.js';
28
+ import type { LoginMailer } from './mailer.js';
29
+ export declare const LOGIN_LINK_MINUTES = 15;
30
+ export declare const SESSION_DAYS = 7;
31
+ export interface ConsoleDeps {
32
+ consoleStore: ConsoleStore;
33
+ identityStore: IdentityStore;
34
+ policy?: PlanPolicy;
35
+ rateLimiter?: RateLimiter;
36
+ rateLimitWindowMs?: number;
37
+ /** Counts the tenant's memories for the overview. */
38
+ store?: Pick<BrainStore, 'count'>;
39
+ usageLedger?: Pick<UsageLedger, 'computeUsage' | 'computeKeyActivity'>;
40
+ stripeApi?: Pick<StripeApi, 'createPortal'>;
41
+ mailer?: LoginMailer;
42
+ /** Where the app is reachable, for links in emails. Falls back to the request's own host. */
43
+ publicBaseUrl?: string;
44
+ /** Directory holding index.html, app.js, styles.css. */
45
+ consoleDir?: string;
46
+ /** Drop the Secure flag on the cookie: plain-http local development only. */
47
+ insecureCookies?: boolean;
48
+ now?: () => number;
49
+ }
50
+ /** Counts attempts per key inside a sliding window. Per instance: enough to blunt abuse, not a security boundary. */
51
+ export declare class AttemptLimiter {
52
+ private readonly max;
53
+ private readonly windowMs;
54
+ private readonly hits;
55
+ constructor(max: number, windowMs: number);
56
+ allow(key: string, now: number): boolean;
57
+ }
58
+ /** The origin the app is served from: configured, else what the proxy in front of us says. */
59
+ export declare function publicBase(req: Request, configured?: string): string;
60
+ export declare const loginLink: (base: string, token: string) => string;
61
+ /** Issues a one-time link for an ACTIVE member; null when the email is not one. Shared with the operator route. */
62
+ export declare function issueLoginLink(store: ConsoleStore, email: string, now: number): Promise<{
63
+ token: string;
64
+ email: string;
65
+ expiresAt: number;
66
+ } | null>;
67
+ export declare function consoleRouter(deps: ConsoleDeps): Router;
68
+ //# sourceMappingURL=consoleRouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consoleRouter.d.ts","sourceRoot":"","sources":["../../../../src/cloud/console/consoleRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAgB,EAAqB,KAAK,OAAO,EAAsC,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAKpH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAuC,KAAK,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAC1G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,YAAY,IAAI,CAAC;AAI9B,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,KAAK,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAClC,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,GAAG,oBAAoB,CAAC,CAAC;IACvE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAC5C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qHAAqH;AACrH,qBAAa,cAAc;IAGvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAH3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;gBAEjC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM;IAEnC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;CAWzC;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,MAA2C,CAAC;AAEpG,mHAAmH;AACnH,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAOrE;AAkBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CA+MvD"}
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Lemma Cloud console — the web app's server side, mounted at /console.
3
+ *
4
+ * GET /console/ the static app (console/index.html, app.js, styles.css)
5
+ * POST /console/api/login {email} asks for a sign-in link: ALWAYS 202, so it cannot tell who is a member
6
+ * POST /console/api/verify {token} spends the link, starts a session (HttpOnly cookie)
7
+ * POST /console/api/logout
8
+ * GET /console/api/me who you are, your tenant's plan, limits, use and (owner/admin) billing
9
+ * GET /console/api/usage owner/admin: requests and tokens by operation and by dev, this month
10
+ * GET /console/api/team owner/admin: members, keys (never a secret), seats
11
+ * POST /console/api/billing/portal owner/admin: Stripe billing-portal link
12
+ *
13
+ * It is a separate identity from the API keys on purpose: a key belongs to a machine and a tenant, a
14
+ * session belongs to a person. Sessions live in the database, so removing a member ends their access at once.
15
+ *
16
+ * Defences, each cheap: the link travels in the URL FRAGMENT (never reaches a server log or a Referer) and is
17
+ * posted by the page; the cookie is HttpOnly + Secure + SameSite=Lax and scoped to /console; every POST needs
18
+ * a custom header and a same-origin Origin (so a cross-site form cannot act); the CSP allows only our own files.
19
+ */
20
+ import express from 'express';
21
+ import path from 'path';
22
+ import { z } from 'zod';
23
+ import { LemmaApiError } from '../../contracts/errors.js';
24
+ import { buildTenantOverview } from '../v2/routes/tenant.js';
25
+ import { hashToken, newToken, normalizeEmail } from './ConsoleStore.js';
26
+ export const LOGIN_LINK_MINUTES = 15;
27
+ export const SESSION_DAYS = 7;
28
+ const COOKIE = 'lemma_console';
29
+ const CSRF_HEADER = 'x-lemma-console';
30
+ /** Counts attempts per key inside a sliding window. Per instance: enough to blunt abuse, not a security boundary. */
31
+ export class AttemptLimiter {
32
+ constructor(max, windowMs) {
33
+ this.max = max;
34
+ this.windowMs = windowMs;
35
+ this.hits = new Map();
36
+ }
37
+ allow(key, now) {
38
+ const recent = (this.hits.get(key) ?? []).filter((t) => now - t < this.windowMs);
39
+ if (recent.length >= this.max) {
40
+ this.hits.set(key, recent);
41
+ return false;
42
+ }
43
+ recent.push(now);
44
+ this.hits.set(key, recent);
45
+ if (this.hits.size > 5000)
46
+ for (const [k, v] of this.hits)
47
+ if (!v.some((t) => now - t < this.windowMs))
48
+ this.hits.delete(k);
49
+ return true;
50
+ }
51
+ }
52
+ /** The origin the app is served from: configured, else what the proxy in front of us says. */
53
+ export function publicBase(req, configured) {
54
+ if (configured)
55
+ return configured.replace(/\/+$/, '');
56
+ const proto = String(req.headers['x-forwarded-proto'] ?? req.protocol).split(',')[0].trim();
57
+ return `${proto}://${req.get('host')}`;
58
+ }
59
+ export const loginLink = (base, token) => `${base}/console/#token=${token}`;
60
+ /** Issues a one-time link for an ACTIVE member; null when the email is not one. Shared with the operator route. */
61
+ export async function issueLoginLink(store, email, now) {
62
+ const member = await store.findMemberByEmail(email);
63
+ if (!member)
64
+ return null;
65
+ const token = newToken();
66
+ const expiresAt = now + LOGIN_LINK_MINUTES * 60000;
67
+ await store.createLoginToken({ tokenHash: hashToken(token), tenantId: member.tenantId, email: member.email, expiresAt });
68
+ return { token, email: member.email, expiresAt };
69
+ }
70
+ const LoginSchema = z.object({ email: z.string().trim().email().max(254) });
71
+ const VerifySchema = z.object({ token: z.string().min(20).max(200) });
72
+ const fail = (status, code, message) => new LemmaApiError({ code, status, message });
73
+ function readCookie(req, name) {
74
+ for (const part of (req.headers.cookie ?? '').split(';')) {
75
+ const i = part.indexOf('=');
76
+ if (i > 0 && part.slice(0, i).trim() === name)
77
+ return part.slice(i + 1).trim();
78
+ }
79
+ return null;
80
+ }
81
+ export function consoleRouter(deps) {
82
+ const clock = deps.now ?? Date.now;
83
+ const loginByIp = new AttemptLimiter(20, 60 * 60000);
84
+ const loginByEmail = new AttemptLimiter(5, LOGIN_LINK_MINUTES * 60000);
85
+ const verifyByIp = new AttemptLimiter(30, 15 * 60000);
86
+ const r = express.Router();
87
+ r.use((_req, res, next) => {
88
+ res.set({
89
+ 'Content-Security-Policy': "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'",
90
+ 'X-Content-Type-Options': 'nosniff',
91
+ 'X-Frame-Options': 'DENY',
92
+ 'Referrer-Policy': 'no-referrer',
93
+ });
94
+ next();
95
+ });
96
+ const api = express.Router();
97
+ api.use((_req, res, next) => {
98
+ res.set('Cache-Control', 'no-store');
99
+ next();
100
+ });
101
+ // Every state-changing call must come from our own page: a header a cross-site form cannot set, and an Origin that matches.
102
+ api.use((req, _res, next) => {
103
+ if (req.method === 'GET')
104
+ return next();
105
+ if (req.headers[CSRF_HEADER] !== '1')
106
+ return next(fail(403, 'forbidden', 'missing console header'));
107
+ const origin = req.headers.origin;
108
+ if (origin && origin !== publicBase(req, deps.publicBaseUrl))
109
+ return next(fail(403, 'forbidden', 'cross-origin request refused'));
110
+ next();
111
+ });
112
+ const wrap = (fn) => (req, res, next) => {
113
+ fn(req, res).catch(next);
114
+ };
115
+ const setCookie = (res, value, maxAgeSeconds) => res.append('Set-Cookie', `${COOKIE}=${value}; HttpOnly; SameSite=Lax; Path=/console; Max-Age=${maxAgeSeconds}${deps.insecureCookies ? '' : '; Secure'}`);
116
+ const requireSession = async (req, _res, next) => {
117
+ try {
118
+ const token = readCookie(req, COOKIE);
119
+ const session = token ? await deps.consoleStore.findSession(hashToken(token), clock()) : null;
120
+ if (!session)
121
+ return next(fail(401, 'unauthenticated', 'sign in required'));
122
+ req.session = session;
123
+ next();
124
+ }
125
+ catch (err) {
126
+ next(err);
127
+ }
128
+ };
129
+ const managerOnly = (req, _res, next) => {
130
+ const { role } = req.session;
131
+ if (role === 'owner' || role === 'admin')
132
+ return next();
133
+ next(fail(403, 'forbidden', 'only an owner or admin can see this'));
134
+ };
135
+ api.post('/login', wrap(async (req, res) => {
136
+ const parsed = LoginSchema.safeParse(req.body);
137
+ if (!parsed.success)
138
+ throw fail(400, 'invalid_request', 'a valid email is required');
139
+ const now = clock();
140
+ const email = normalizeEmail(parsed.data.email);
141
+ if (!loginByIp.allow(req.ip ?? 'unknown', now) || !loginByEmail.allow(email, now)) {
142
+ res.status(429).set('Retry-After', '900').json({ error: { code: 'rate_limited', status: 429, message: 'too many sign-in requests, try again in a few minutes' } });
143
+ return;
144
+ }
145
+ const issued = await issueLoginLink(deps.consoleStore, email, now);
146
+ if (issued && deps.mailer) {
147
+ const link = loginLink(publicBase(req, deps.publicBaseUrl), issued.token);
148
+ // Not awaited: an existing and an unknown email take the same time, and a mail outage tells no one anything.
149
+ deps.mailer.sendLoginLink(issued.email, link, LOGIN_LINK_MINUTES).catch((err) => {
150
+ // eslint-disable-next-line no-console
151
+ console.error('[lemma:console] sign-in email failed:', err.message);
152
+ });
153
+ }
154
+ res.status(202).json({ ok: true });
155
+ }));
156
+ api.post('/verify', wrap(async (req, res) => {
157
+ const parsed = VerifySchema.safeParse(req.body);
158
+ if (!parsed.success || !verifyByIp.allow(req.ip ?? 'unknown', clock()))
159
+ throw fail(401, 'unauthenticated', 'this sign-in link is not valid');
160
+ const now = clock();
161
+ const spent = await deps.consoleStore.consumeLoginToken(hashToken(parsed.data.token), now);
162
+ const member = spent ? await deps.consoleStore.findMemberByEmail(spent.email) : null;
163
+ if (!spent || !member || member.tenantId !== spent.tenantId)
164
+ throw fail(401, 'unauthenticated', 'this sign-in link is not valid or has expired');
165
+ const session = newToken();
166
+ await deps.consoleStore.createSession({ tokenHash: hashToken(session), tenantId: member.tenantId, email: member.email, expiresAt: now + SESSION_DAYS * 86400000 });
167
+ setCookie(res, session, SESSION_DAYS * 86400);
168
+ res.json({ ok: true });
169
+ }));
170
+ api.post('/logout', wrap(async (req, res) => {
171
+ const token = readCookie(req, COOKIE);
172
+ if (token)
173
+ await deps.consoleStore.deleteSession(hashToken(token));
174
+ setCookie(res, '', 0);
175
+ res.json({ ok: true });
176
+ }));
177
+ api.get('/me', requireSession, wrap(async (req, res) => {
178
+ const { tenantId, email, role } = req.session;
179
+ const tenant = await deps.identityStore.getTenant(tenantId);
180
+ if (!tenant)
181
+ throw fail(404, 'not_found', 'tenant not found');
182
+ const overview = await buildTenantOverview(deps, tenant);
183
+ const manager = role === 'owner' || role === 'admin';
184
+ // A plain member sees the plan and the limits; money (status, renewal, late payment) is for owner and admin.
185
+ res.json({ email, role, canManage: manager, tenant: manager ? overview : { ...overview, billing: { status: null, currentPeriodEnd: null, pastDueSince: null } } });
186
+ }));
187
+ api.get('/usage', requireSession, managerOnly, wrap(async (req, res) => {
188
+ const { tenantId } = req.session;
189
+ if (!deps.usageLedger?.computeKeyActivity)
190
+ throw new LemmaApiError({ code: 'not_implemented', status: 501, message: 'usage ledger unavailable' });
191
+ const monthStart = new Date(clock());
192
+ const since = Date.UTC(monthStart.getUTCFullYear(), monthStart.getUTCMonth(), 1);
193
+ const [usage, activity, keys] = await Promise.all([
194
+ deps.usageLedger.computeUsage({ tenantId, since }),
195
+ deps.usageLedger.computeKeyActivity({ tenantId, since }),
196
+ deps.identityStore.listKeys(tenantId),
197
+ ]);
198
+ const names = new Map(keys.map((k) => [k.id, k]));
199
+ res.json({
200
+ since,
201
+ metrics: usage.metrics,
202
+ keys: activity.map((a) => ({
203
+ keyId: a.keyId,
204
+ name: names.get(a.keyId)?.name ?? null,
205
+ active: names.get(a.keyId)?.active ?? false,
206
+ requests: a.requests,
207
+ tokens: a.tokens,
208
+ byOperation: a.byOperation,
209
+ })),
210
+ });
211
+ }));
212
+ api.get('/team', requireSession, managerOnly, wrap(async (req, res) => {
213
+ const { tenantId } = req.session;
214
+ const tenant = await deps.identityStore.getTenant(tenantId);
215
+ if (!tenant)
216
+ throw fail(404, 'not_found', 'tenant not found');
217
+ const now = clock();
218
+ const [members, keys] = await Promise.all([deps.consoleStore.listMembers(tenantId), deps.identityStore.listKeys(tenantId)]);
219
+ const used = keys.filter((k) => k.active && (k.expiresAt === null || k.expiresAt > now)).length;
220
+ res.json({
221
+ seats: { used, limit: (deps.policy ? deps.policy.limitsFor(tenant.plan) : { seats: 0 }).seats },
222
+ members: members.map((m) => ({ email: m.email, role: m.role })),
223
+ // A key is shown by its label and state only: the hash and the secret never leave the database.
224
+ keys: keys.map((k) => ({ id: k.id, name: k.name, active: k.active, createdAt: k.createdAt, revokedAt: k.revokedAt })),
225
+ });
226
+ }));
227
+ api.post('/billing/portal', requireSession, managerOnly, wrap(async (req, res) => {
228
+ const { tenantId } = req.session;
229
+ const tenant = await deps.identityStore.getTenant(tenantId);
230
+ if (!tenant)
231
+ throw fail(404, 'not_found', 'tenant not found');
232
+ if (!deps.stripeApi || !tenant.billing.customerId) {
233
+ throw new LemmaApiError({ code: 'invalid_request', status: 409, message: 'there is no subscription to manage yet' });
234
+ }
235
+ res.json({ url: (await deps.stripeApi.createPortal(tenant.billing.customerId)).url });
236
+ }));
237
+ r.use('/api', api);
238
+ // The static app. Unknown paths under /console fall back to the page itself (it routes on the fragment).
239
+ const dir = path.resolve(deps.consoleDir ?? path.join(process.cwd(), 'console'));
240
+ r.use(express.static(dir, { index: 'index.html', maxAge: 0, fallthrough: true }));
241
+ r.get('/', (_req, res) => res.sendFile(path.join(dir, 'index.html')));
242
+ // JSON errors for the API; the app never sees a stack or an HTML error page.
243
+ r.use('/api', (err, _req, res, next) => {
244
+ if (err instanceof LemmaApiError) {
245
+ res.status(err.status).json(err.toJSON());
246
+ return;
247
+ }
248
+ next(err);
249
+ });
250
+ return r;
251
+ }
252
+ //# sourceMappingURL=consoleRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consoleRouter.js","sourceRoot":"","sources":["../../../../src/cloud/console/consoleRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Lemma Cloud console — the sign-in email. Optional: without RESEND_API_KEY nothing is sent, and the
3
+ * operator hands the link over by hand (POST /v2/admin/tenants/:id/members/:email/login-link).
4
+ *
5
+ * The link is the only secret in the message and it is single use and short lived. It is never logged.
6
+ */
7
+ export interface LoginMailer {
8
+ sendLoginLink(to: string, link: string, minutes: number): Promise<void>;
9
+ }
10
+ export interface ResendConfig {
11
+ apiKey: string;
12
+ from: string;
13
+ fetchImpl?: typeof fetch;
14
+ }
15
+ export declare function resendMailerFromEnv(env?: NodeJS.ProcessEnv): LoginMailer | undefined;
16
+ export declare class ResendMailer implements LoginMailer {
17
+ private readonly config;
18
+ private readonly fetchImpl;
19
+ constructor(config: ResendConfig);
20
+ sendLoginLink(to: string, link: string, minutes: number): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=mailer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mailer.d.ts","sourceRoot":"","sources":["../../../../src/cloud/console/mailer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,GAAG,SAAS,CAIjG;AAED,qBAAa,YAAa,YAAW,WAAW;IAElC,OAAO,CAAC,QAAQ,CAAC,MAAM;IADnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBACZ,MAAM,EAAE,YAAY;IAI3C,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAiB9E"}
@@ -0,0 +1,30 @@
1
+ export function resendMailerFromEnv(env = process.env) {
2
+ const apiKey = env.RESEND_API_KEY;
3
+ if (!apiKey)
4
+ return undefined;
5
+ return new ResendMailer({ apiKey, from: env.CONSOLE_MAIL_FROM || 'Lemma <hello@nxus.studio>' });
6
+ }
7
+ export class ResendMailer {
8
+ constructor(config) {
9
+ this.config = config;
10
+ this.fetchImpl = config.fetchImpl ?? fetch;
11
+ }
12
+ async sendLoginLink(to, link, minutes) {
13
+ const res = await this.fetchImpl('https://api.resend.com/emails', {
14
+ method: 'POST',
15
+ headers: { Authorization: `Bearer ${this.config.apiKey}`, 'Content-Type': 'application/json' },
16
+ body: JSON.stringify({
17
+ from: this.config.from,
18
+ to: [to],
19
+ subject: 'Your Lemma Cloud sign-in link / Tu enlace de acceso a Lemma Cloud',
20
+ text: `Sign in to Lemma Cloud (valid ${minutes} minutes, works once):\n${link}\n\n` +
21
+ `Entra a Lemma Cloud (válido ${minutes} minutos, funciona una vez):\n${link}\n\n` +
22
+ `If you did not ask for this, ignore this email. / Si no lo pediste, ignora este correo.`,
23
+ }),
24
+ });
25
+ // The status only: the response body and the request (which holds the link) stay out of any log.
26
+ if (!res.ok)
27
+ throw new Error(`mail provider answered ${res.status}`);
28
+ }
29
+ }
30
+ //# sourceMappingURL=mailer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mailer.js","sourceRoot":"","sources":["../../../../src/cloud/console/mailer.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,MAAM,MAAM,GAAG,GAAG,CAAC,cAAc,CAAC;IAClC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,OAAO,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,iBAAiB,IAAI,2BAA2B,EAAE,CAAC,CAAC;AAClG,CAAC;AAED,MAAM,OAAO,YAAY;IAEvB,YAA6B,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;QAC/C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,EAAU,EAAE,IAAY,EAAE,OAAe;QAC3D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,+BAA+B,EAAE;YAChE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC9F,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;gBACtB,EAAE,EAAE,CAAC,EAAE,CAAC;gBACR,OAAO,EAAE,mEAAmE;gBAC5E,IAAI,EACF,iCAAiC,OAAO,2BAA2B,IAAI,MAAM;oBAC7E,+BAA+B,OAAO,iCAAiC,IAAI,MAAM;oBACjF,yFAAyF;aAC5F,CAAC;SACH,CAAC,CAAC;QACH,iGAAiG;QACjG,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;CACF"}
@@ -9,7 +9,16 @@
9
9
  * This module owns the plan table. The DB migration only stores tenancy; keeping
10
10
  * a second copy of the limits in SQL would guarantee drift.
11
11
  */
12
- export type PlanId = 'free' | 'pro' | 'scale';
12
+ /**
13
+ * Cloud plans. `vinel` is the team tier (every seat also unlocks the local Pro tools) and `regnum`
14
+ * is the large-organisation tier. They used to be `pro` and `scale`; `pro` now means only the local
15
+ * Pro license, so the two are never confused. `internal` is not sold: it is for the maintainers' own
16
+ * accounts (huge but finite ceilings, because Infinity is banned), assigned only through the admin API,
17
+ * and the Stripe webhook never touches a tenant on it. Add a plan here and the type, the admin API validation
18
+ * and the SQL CHECK (a new migration) follow from this list.
19
+ */
20
+ export declare const PLAN_IDS: readonly ["free", "vinel", "regnum", "internal"];
21
+ export type PlanId = (typeof PLAN_IDS)[number];
13
22
  export interface PlanLimits {
14
23
  /** Active AND verified memories the tenant may keep. */
15
24
  activeMemories: number;
@@ -28,6 +37,12 @@ export declare const RATE_LIMIT_WINDOW_MS: number;
28
37
  export declare const PLAN_UPGRADE_URL: Readonly<Record<PlanId, string>>;
29
38
  /** Single source of truth for plan ceilings. Every value finite and > 0. */
30
39
  export declare const PLAN_LIMITS: Readonly<Record<PlanId, PlanLimits>>;
40
+ /**
41
+ * Whether a seat on the plan also unlocks the local Pro tools. A Record over PlanId, so adding a plan
42
+ * to PLAN_IDS without deciding this does not compile. The client never decides it: it asks the server
43
+ * (GET /v2/entitlement), so changing a plan here changes what every connected dev gets.
44
+ */
45
+ export declare const PLAN_INCLUDES_PRO: Readonly<Record<PlanId, boolean>>;
31
46
  export declare const DEFAULT_PLAN: PlanId;
32
47
  /**
33
48
  * The `Infinity` elimination check, exported so tests can prove it (and the
@@ -1 +1 @@
1
- {"version":3,"file":"PlanPolicy.d.ts","sourceRoot":"","sources":["../../../../src/cloud/identity/PlanPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,cAAc,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,oBAAoB,QAAsB,CAAC;AAExD,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAI5D,CAAC;AAEH,4EAA4E;AAC5E,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAyB3D,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,MAAe,CAAC;AAU3C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,MAAM,EAAE,CAY/E;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,CAAC;AAE3F,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE;QACL,IAAI,EAAE,gBAAgB,CAAC;QACvB,MAAM,EAAE,GAAG,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,SAAS,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,yFAAyF;QACzF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,GAAE,MAAM,GAAG,IAAW,GAAG,cAAc,CAcxG;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;gBAExC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAA6C;IAQ1F,2EAA2E;IAC3E,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;IAInC,wEAAwE;IACxE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,GAAG,UAAU;IAiB5E,kEAAkE;IAClE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU;IAgBzD,OAAO,CAAC,WAAW;CAcpB"}
1
+ {"version":3,"file":"PlanPolicy.d.ts","sourceRoot":"","sources":["../../../../src/cloud/identity/PlanPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,kDAAmD,CAAC;AACzE,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,cAAc,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,oBAAoB,QAAsB,CAAC;AAExD,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK5D,CAAC;AAEH,4EAA4E;AAC5E,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAiC3D,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAK9D,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,MAAe,CAAC;AAU3C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,MAAM,EAAE,CAY/E;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,CAAC;AAE3F,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE;QACL,IAAI,EAAE,gBAAgB,CAAC;QACvB,MAAM,EAAE,GAAG,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,SAAS,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,yFAAyF;QACzF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,GAAE,MAAM,GAAG,IAAW,GAAG,cAAc,CAcxG;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;gBAExC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAA6C;IAQ1F,2EAA2E;IAC3E,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;IAInC,wEAAwE;IACxE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,GAAG,UAAU;IAiB5E,kEAAkE;IAClE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU;IAgBzD,OAAO,CAAC,WAAW;CAcpB"}