@nxuss/lemma 1.43.0 → 1.45.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 (388) hide show
  1. package/README.md +26 -8
  2. package/bin/brain-ingest.js +48 -13
  3. package/bin/cloud.js +228 -0
  4. package/dist/cjs/cli/hostHooks.d.ts +44 -7
  5. package/dist/cjs/cli/hostHooks.d.ts.map +1 -1
  6. package/dist/cjs/cli/hostHooks.js +201 -11
  7. package/dist/cjs/cli/hostHooks.js.map +1 -1
  8. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  9. package/dist/cjs/cli/lemma-proxy.js +13 -16
  10. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  11. package/dist/cjs/cloud/CloudBrainClient.d.ts +52 -0
  12. package/dist/cjs/cloud/CloudBrainClient.d.ts.map +1 -0
  13. package/dist/cjs/cloud/CloudBrainClient.js +161 -0
  14. package/dist/cjs/cloud/CloudBrainClient.js.map +1 -0
  15. package/dist/cjs/cloud/CloudConfig.d.ts +41 -0
  16. package/dist/cjs/cloud/CloudConfig.d.ts.map +1 -0
  17. package/dist/cjs/cloud/CloudConfig.js +133 -0
  18. package/dist/cjs/cloud/CloudConfig.js.map +1 -0
  19. package/dist/cjs/cloud/CloudEntitlement.d.ts +55 -0
  20. package/dist/cjs/cloud/CloudEntitlement.d.ts.map +1 -0
  21. package/dist/cjs/cloud/CloudEntitlement.js +174 -0
  22. package/dist/cjs/cloud/CloudEntitlement.js.map +1 -0
  23. package/dist/cjs/cloud/billing/stripeApi.d.ts +43 -0
  24. package/dist/cjs/cloud/billing/stripeApi.d.ts.map +1 -0
  25. package/dist/cjs/cloud/billing/stripeApi.js +116 -0
  26. package/dist/cjs/cloud/billing/stripeApi.js.map +1 -0
  27. package/dist/cjs/cloud/billing/stripeWebhook.d.ts +35 -0
  28. package/dist/cjs/cloud/billing/stripeWebhook.d.ts.map +1 -0
  29. package/dist/cjs/cloud/billing/stripeWebhook.js +190 -0
  30. package/dist/cjs/cloud/billing/stripeWebhook.js.map +1 -0
  31. package/dist/cjs/cloud/console/ConsoleStore.d.ts +111 -0
  32. package/dist/cjs/cloud/console/ConsoleStore.d.ts.map +1 -0
  33. package/dist/cjs/cloud/console/ConsoleStore.js +172 -0
  34. package/dist/cjs/cloud/console/ConsoleStore.js.map +1 -0
  35. package/dist/cjs/cloud/console/consoleRouter.d.ts +68 -0
  36. package/dist/cjs/cloud/console/consoleRouter.d.ts.map +1 -0
  37. package/dist/cjs/cloud/console/consoleRouter.js +301 -0
  38. package/dist/cjs/cloud/console/consoleRouter.js.map +1 -0
  39. package/dist/cjs/cloud/console/mailer.d.ts +22 -0
  40. package/dist/cjs/cloud/console/mailer.d.ts.map +1 -0
  41. package/dist/cjs/cloud/console/mailer.js +35 -0
  42. package/dist/cjs/cloud/console/mailer.js.map +1 -0
  43. package/dist/cjs/cloud/identity/PlanPolicy.d.ts +42 -6
  44. package/dist/cjs/cloud/identity/PlanPolicy.d.ts.map +1 -1
  45. package/dist/cjs/cloud/identity/PlanPolicy.js +102 -22
  46. package/dist/cjs/cloud/identity/PlanPolicy.js.map +1 -1
  47. package/dist/cjs/cloud/identity/RateLimiter.d.ts +21 -1
  48. package/dist/cjs/cloud/identity/RateLimiter.d.ts.map +1 -1
  49. package/dist/cjs/cloud/identity/RateLimiter.js +59 -2
  50. package/dist/cjs/cloud/identity/RateLimiter.js.map +1 -1
  51. package/dist/cjs/cloud/identity/TenantResolver.d.ts +6 -1
  52. package/dist/cjs/cloud/identity/TenantResolver.d.ts.map +1 -1
  53. package/dist/cjs/cloud/identity/TenantResolver.js +1 -1
  54. package/dist/cjs/cloud/identity/TenantResolver.js.map +1 -1
  55. package/dist/cjs/cloud/identity/authenticateV2.d.ts.map +1 -1
  56. package/dist/cjs/cloud/identity/authenticateV2.js +7 -4
  57. package/dist/cjs/cloud/identity/authenticateV2.js.map +1 -1
  58. package/dist/cjs/cloud/identity/identityStore.d.ts +96 -10
  59. package/dist/cjs/cloud/identity/identityStore.d.ts.map +1 -1
  60. package/dist/cjs/cloud/identity/identityStore.js +203 -4
  61. package/dist/cjs/cloud/identity/identityStore.js.map +1 -1
  62. package/dist/cjs/cloud/metering/PostgresLedgerStore.d.ts +18 -0
  63. package/dist/cjs/cloud/metering/PostgresLedgerStore.d.ts.map +1 -0
  64. package/dist/cjs/cloud/metering/PostgresLedgerStore.js +56 -0
  65. package/dist/cjs/cloud/metering/PostgresLedgerStore.js.map +1 -0
  66. package/dist/cjs/cloud/metering/UsageLedger.d.ts +74 -0
  67. package/dist/cjs/cloud/metering/UsageLedger.d.ts.map +1 -1
  68. package/dist/cjs/cloud/metering/UsageLedger.js +122 -17
  69. package/dist/cjs/cloud/metering/UsageLedger.js.map +1 -1
  70. package/dist/cjs/cloud/metering/index.d.ts +1 -0
  71. package/dist/cjs/cloud/metering/index.d.ts.map +1 -1
  72. package/dist/cjs/cloud/metering/index.js +1 -0
  73. package/dist/cjs/cloud/metering/index.js.map +1 -1
  74. package/dist/cjs/cloud/store/FileBrainStore.d.ts +6 -1
  75. package/dist/cjs/cloud/store/FileBrainStore.d.ts.map +1 -1
  76. package/dist/cjs/cloud/store/FileBrainStore.js +8 -0
  77. package/dist/cjs/cloud/store/FileBrainStore.js.map +1 -1
  78. package/dist/cjs/cloud/store/PostgresBrainStore.d.ts +11 -1
  79. package/dist/cjs/cloud/store/PostgresBrainStore.d.ts.map +1 -1
  80. package/dist/cjs/cloud/store/PostgresBrainStore.js +32 -0
  81. package/dist/cjs/cloud/store/PostgresBrainStore.js.map +1 -1
  82. package/dist/cjs/cloud/store/memorySummary.d.ts +29 -0
  83. package/dist/cjs/cloud/store/memorySummary.d.ts.map +1 -0
  84. package/dist/cjs/cloud/store/memorySummary.js +66 -0
  85. package/dist/cjs/cloud/store/memorySummary.js.map +1 -0
  86. package/dist/cjs/cloud/v2/app.d.ts.map +1 -1
  87. package/dist/cjs/cloud/v2/app.js +6 -0
  88. package/dist/cjs/cloud/v2/app.js.map +1 -1
  89. package/dist/cjs/cloud/v2/inputGuard.d.ts +23 -0
  90. package/dist/cjs/cloud/v2/inputGuard.d.ts.map +1 -0
  91. package/dist/cjs/cloud/v2/inputGuard.js +71 -0
  92. package/dist/cjs/cloud/v2/inputGuard.js.map +1 -0
  93. package/dist/cjs/cloud/v2/routes/admin.d.ts +24 -0
  94. package/dist/cjs/cloud/v2/routes/admin.d.ts.map +1 -0
  95. package/dist/cjs/cloud/v2/routes/admin.js +344 -0
  96. package/dist/cjs/cloud/v2/routes/admin.js.map +1 -0
  97. package/dist/cjs/cloud/v2/routes/entitlement.d.ts +13 -0
  98. package/dist/cjs/cloud/v2/routes/entitlement.d.ts.map +1 -0
  99. package/dist/cjs/cloud/v2/routes/entitlement.js +24 -0
  100. package/dist/cjs/cloud/v2/routes/entitlement.js.map +1 -0
  101. package/dist/cjs/cloud/v2/routes/index.d.ts +14 -1
  102. package/dist/cjs/cloud/v2/routes/index.d.ts.map +1 -1
  103. package/dist/cjs/cloud/v2/routes/index.js +36 -0
  104. package/dist/cjs/cloud/v2/routes/index.js.map +1 -1
  105. package/dist/cjs/cloud/v2/routes/memories.d.ts +21 -2
  106. package/dist/cjs/cloud/v2/routes/memories.d.ts.map +1 -1
  107. package/dist/cjs/cloud/v2/routes/memories.js +77 -0
  108. package/dist/cjs/cloud/v2/routes/memories.js.map +1 -1
  109. package/dist/cjs/cloud/v2/routes/recall.d.ts +1 -0
  110. package/dist/cjs/cloud/v2/routes/recall.d.ts.map +1 -1
  111. package/dist/cjs/cloud/v2/routes/recall.js +4 -0
  112. package/dist/cjs/cloud/v2/routes/recall.js.map +1 -1
  113. package/dist/cjs/cloud/v2/routes/tenant.d.ts +36 -0
  114. package/dist/cjs/cloud/v2/routes/tenant.d.ts.map +1 -0
  115. package/dist/cjs/cloud/v2/routes/tenant.js +65 -0
  116. package/dist/cjs/cloud/v2/routes/tenant.js.map +1 -0
  117. package/dist/cjs/cloud/v2/routes/usage.d.ts +1 -1
  118. package/dist/cjs/cloud/v2/routes/usage.d.ts.map +1 -1
  119. package/dist/cjs/cloud/v2/routes/verify.d.ts +1 -0
  120. package/dist/cjs/cloud/v2/routes/verify.d.ts.map +1 -1
  121. package/dist/cjs/cloud/v2/routes/verify.js +4 -0
  122. package/dist/cjs/cloud/v2/routes/verify.js.map +1 -1
  123. package/dist/cjs/cloud/v2/server.d.ts +9 -3
  124. package/dist/cjs/cloud/v2/server.d.ts.map +1 -1
  125. package/dist/cjs/cloud/v2/server.js +36 -2
  126. package/dist/cjs/cloud/v2/server.js.map +1 -1
  127. package/dist/cjs/cloud/v2/usageRecorder.d.ts +19 -0
  128. package/dist/cjs/cloud/v2/usageRecorder.d.ts.map +1 -0
  129. package/dist/cjs/cloud/v2/usageRecorder.js +42 -0
  130. package/dist/cjs/cloud/v2/usageRecorder.js.map +1 -0
  131. package/dist/cjs/contracts/api-v2.types.d.ts +92 -2
  132. package/dist/cjs/contracts/api-v2.types.d.ts.map +1 -1
  133. package/dist/cjs/contracts/store.d.ts +37 -0
  134. package/dist/cjs/contracts/store.d.ts.map +1 -1
  135. package/dist/cjs/mcp/index.js +7 -1
  136. package/dist/cjs/mcp/index.js.map +1 -1
  137. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  138. package/dist/cjs/mcp/tools/memory.js +74 -4
  139. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  140. package/dist/cjs/mcp/tools/misc.d.ts.map +1 -1
  141. package/dist/cjs/mcp/tools/misc.js +2 -1
  142. package/dist/cjs/mcp/tools/misc.js.map +1 -1
  143. package/dist/cjs/mcp/tools/workspace.d.ts.map +1 -1
  144. package/dist/cjs/mcp/tools/workspace.js +4 -1
  145. package/dist/cjs/mcp/tools/workspace.js.map +1 -1
  146. package/dist/cjs/mcp/tools.d.ts +10 -0
  147. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  148. package/dist/cjs/mcp/tools.js +47 -12
  149. package/dist/cjs/mcp/tools.js.map +1 -1
  150. package/dist/cjs/proxy/KeyManager.d.ts.map +1 -1
  151. package/dist/cjs/proxy/KeyManager.js +5 -0
  152. package/dist/cjs/proxy/KeyManager.js.map +1 -1
  153. package/dist/cjs/subconscious/CloudBrain.d.ts +77 -0
  154. package/dist/cjs/subconscious/CloudBrain.d.ts.map +1 -0
  155. package/dist/cjs/subconscious/CloudBrain.js +347 -0
  156. package/dist/cjs/subconscious/CloudBrain.js.map +1 -0
  157. package/dist/cjs/subconscious/HostRecall.d.ts.map +1 -1
  158. package/dist/cjs/subconscious/HostRecall.js +11 -4
  159. package/dist/cjs/subconscious/HostRecall.js.map +1 -1
  160. package/dist/cjs/subconscious/ProjectIdentity.d.ts +9 -0
  161. package/dist/cjs/subconscious/ProjectIdentity.d.ts.map +1 -0
  162. package/dist/cjs/subconscious/ProjectIdentity.js +63 -0
  163. package/dist/cjs/subconscious/ProjectIdentity.js.map +1 -0
  164. package/dist/cjs/subconscious/TeamBrain.d.ts +9 -3
  165. package/dist/cjs/subconscious/TeamBrain.d.ts.map +1 -1
  166. package/dist/cjs/subconscious/TeamBrain.js +39 -5
  167. package/dist/cjs/subconscious/TeamBrain.js.map +1 -1
  168. package/dist/cjs/utils/FixCapture.d.ts +7 -5
  169. package/dist/cjs/utils/FixCapture.d.ts.map +1 -1
  170. package/dist/cjs/utils/FixCapture.js +64 -32
  171. package/dist/cjs/utils/FixCapture.js.map +1 -1
  172. package/dist/cjs/utils/NoTerminal.d.ts +27 -0
  173. package/dist/cjs/utils/NoTerminal.d.ts.map +1 -0
  174. package/dist/cjs/utils/NoTerminal.js +37 -0
  175. package/dist/cjs/utils/NoTerminal.js.map +1 -0
  176. package/dist/cjs/utils/OpenCodeSession.d.ts +70 -0
  177. package/dist/cjs/utils/OpenCodeSession.d.ts.map +1 -0
  178. package/dist/cjs/utils/OpenCodeSession.js +154 -0
  179. package/dist/cjs/utils/OpenCodeSession.js.map +1 -0
  180. package/dist/cjs/utils/ProLicense.d.ts.map +1 -1
  181. package/dist/cjs/utils/ProLicense.js +11 -3
  182. package/dist/cjs/utils/ProLicense.js.map +1 -1
  183. package/dist/cjs/utils/SessionCapture.d.ts +31 -7
  184. package/dist/cjs/utils/SessionCapture.d.ts.map +1 -1
  185. package/dist/cjs/utils/SessionCapture.js +185 -32
  186. package/dist/cjs/utils/SessionCapture.js.map +1 -1
  187. package/dist/cjs/utils/StopNudge.d.ts +8 -0
  188. package/dist/cjs/utils/StopNudge.d.ts.map +1 -0
  189. package/dist/cjs/utils/StopNudge.js +93 -0
  190. package/dist/cjs/utils/StopNudge.js.map +1 -0
  191. package/dist/cjs/utils/TestAutofixInterceptor.d.ts.map +1 -1
  192. package/dist/cjs/utils/TestAutofixInterceptor.js +2 -0
  193. package/dist/cjs/utils/TestAutofixInterceptor.js.map +1 -1
  194. package/dist/esm/cli/hostHooks.d.ts +44 -7
  195. package/dist/esm/cli/hostHooks.d.ts.map +1 -1
  196. package/dist/esm/cli/hostHooks.js +199 -10
  197. package/dist/esm/cli/hostHooks.js.map +1 -1
  198. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  199. package/dist/esm/cli/lemma-proxy.js +14 -17
  200. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  201. package/dist/esm/cloud/CloudBrainClient.d.ts +52 -0
  202. package/dist/esm/cloud/CloudBrainClient.d.ts.map +1 -0
  203. package/dist/esm/cloud/CloudBrainClient.js +153 -0
  204. package/dist/esm/cloud/CloudBrainClient.js.map +1 -0
  205. package/dist/esm/cloud/CloudConfig.d.ts +41 -0
  206. package/dist/esm/cloud/CloudConfig.d.ts.map +1 -0
  207. package/dist/esm/cloud/CloudConfig.js +118 -0
  208. package/dist/esm/cloud/CloudConfig.js.map +1 -0
  209. package/dist/esm/cloud/CloudEntitlement.d.ts +55 -0
  210. package/dist/esm/cloud/CloudEntitlement.d.ts.map +1 -0
  211. package/dist/esm/cloud/CloudEntitlement.js +159 -0
  212. package/dist/esm/cloud/CloudEntitlement.js.map +1 -0
  213. package/dist/esm/cloud/billing/stripeApi.d.ts +43 -0
  214. package/dist/esm/cloud/billing/stripeApi.d.ts.map +1 -0
  215. package/dist/esm/cloud/billing/stripeApi.js +108 -0
  216. package/dist/esm/cloud/billing/stripeApi.js.map +1 -0
  217. package/dist/esm/cloud/billing/stripeWebhook.d.ts +35 -0
  218. package/dist/esm/cloud/billing/stripeWebhook.d.ts.map +1 -0
  219. package/dist/esm/cloud/billing/stripeWebhook.js +181 -0
  220. package/dist/esm/cloud/billing/stripeWebhook.js.map +1 -0
  221. package/dist/esm/cloud/console/ConsoleStore.d.ts +111 -0
  222. package/dist/esm/cloud/console/ConsoleStore.d.ts.map +1 -0
  223. package/dist/esm/cloud/console/ConsoleStore.js +161 -0
  224. package/dist/esm/cloud/console/ConsoleStore.js.map +1 -0
  225. package/dist/esm/cloud/console/consoleRouter.d.ts +68 -0
  226. package/dist/esm/cloud/console/consoleRouter.d.ts.map +1 -0
  227. package/dist/esm/cloud/console/consoleRouter.js +290 -0
  228. package/dist/esm/cloud/console/consoleRouter.js.map +1 -0
  229. package/dist/esm/cloud/console/mailer.d.ts +22 -0
  230. package/dist/esm/cloud/console/mailer.d.ts.map +1 -0
  231. package/dist/esm/cloud/console/mailer.js +30 -0
  232. package/dist/esm/cloud/console/mailer.js.map +1 -0
  233. package/dist/esm/cloud/identity/PlanPolicy.d.ts +42 -6
  234. package/dist/esm/cloud/identity/PlanPolicy.d.ts.map +1 -1
  235. package/dist/esm/cloud/identity/PlanPolicy.js +100 -21
  236. package/dist/esm/cloud/identity/PlanPolicy.js.map +1 -1
  237. package/dist/esm/cloud/identity/RateLimiter.d.ts +21 -1
  238. package/dist/esm/cloud/identity/RateLimiter.d.ts.map +1 -1
  239. package/dist/esm/cloud/identity/RateLimiter.js +57 -2
  240. package/dist/esm/cloud/identity/RateLimiter.js.map +1 -1
  241. package/dist/esm/cloud/identity/TenantResolver.d.ts +6 -1
  242. package/dist/esm/cloud/identity/TenantResolver.d.ts.map +1 -1
  243. package/dist/esm/cloud/identity/TenantResolver.js +1 -1
  244. package/dist/esm/cloud/identity/TenantResolver.js.map +1 -1
  245. package/dist/esm/cloud/identity/authenticateV2.d.ts.map +1 -1
  246. package/dist/esm/cloud/identity/authenticateV2.js +7 -4
  247. package/dist/esm/cloud/identity/authenticateV2.js.map +1 -1
  248. package/dist/esm/cloud/identity/identityStore.d.ts +96 -10
  249. package/dist/esm/cloud/identity/identityStore.d.ts.map +1 -1
  250. package/dist/esm/cloud/identity/identityStore.js +199 -3
  251. package/dist/esm/cloud/identity/identityStore.js.map +1 -1
  252. package/dist/esm/cloud/metering/PostgresLedgerStore.d.ts +18 -0
  253. package/dist/esm/cloud/metering/PostgresLedgerStore.d.ts.map +1 -0
  254. package/dist/esm/cloud/metering/PostgresLedgerStore.js +52 -0
  255. package/dist/esm/cloud/metering/PostgresLedgerStore.js.map +1 -0
  256. package/dist/esm/cloud/metering/UsageLedger.d.ts +74 -0
  257. package/dist/esm/cloud/metering/UsageLedger.d.ts.map +1 -1
  258. package/dist/esm/cloud/metering/UsageLedger.js +119 -16
  259. package/dist/esm/cloud/metering/UsageLedger.js.map +1 -1
  260. package/dist/esm/cloud/metering/index.d.ts +1 -0
  261. package/dist/esm/cloud/metering/index.d.ts.map +1 -1
  262. package/dist/esm/cloud/metering/index.js +1 -0
  263. package/dist/esm/cloud/metering/index.js.map +1 -1
  264. package/dist/esm/cloud/store/FileBrainStore.d.ts +6 -1
  265. package/dist/esm/cloud/store/FileBrainStore.d.ts.map +1 -1
  266. package/dist/esm/cloud/store/FileBrainStore.js +8 -0
  267. package/dist/esm/cloud/store/FileBrainStore.js.map +1 -1
  268. package/dist/esm/cloud/store/PostgresBrainStore.d.ts +11 -1
  269. package/dist/esm/cloud/store/PostgresBrainStore.d.ts.map +1 -1
  270. package/dist/esm/cloud/store/PostgresBrainStore.js +32 -0
  271. package/dist/esm/cloud/store/PostgresBrainStore.js.map +1 -1
  272. package/dist/esm/cloud/store/memorySummary.d.ts +29 -0
  273. package/dist/esm/cloud/store/memorySummary.d.ts.map +1 -0
  274. package/dist/esm/cloud/store/memorySummary.js +60 -0
  275. package/dist/esm/cloud/store/memorySummary.js.map +1 -0
  276. package/dist/esm/cloud/v2/app.d.ts.map +1 -1
  277. package/dist/esm/cloud/v2/app.js +6 -0
  278. package/dist/esm/cloud/v2/app.js.map +1 -1
  279. package/dist/esm/cloud/v2/inputGuard.d.ts +23 -0
  280. package/dist/esm/cloud/v2/inputGuard.d.ts.map +1 -0
  281. package/dist/esm/cloud/v2/inputGuard.js +63 -0
  282. package/dist/esm/cloud/v2/inputGuard.js.map +1 -0
  283. package/dist/esm/cloud/v2/routes/admin.d.ts +24 -0
  284. package/dist/esm/cloud/v2/routes/admin.d.ts.map +1 -0
  285. package/dist/esm/cloud/v2/routes/admin.js +337 -0
  286. package/dist/esm/cloud/v2/routes/admin.js.map +1 -0
  287. package/dist/esm/cloud/v2/routes/entitlement.d.ts +13 -0
  288. package/dist/esm/cloud/v2/routes/entitlement.d.ts.map +1 -0
  289. package/dist/esm/cloud/v2/routes/entitlement.js +21 -0
  290. package/dist/esm/cloud/v2/routes/entitlement.js.map +1 -0
  291. package/dist/esm/cloud/v2/routes/index.d.ts +14 -1
  292. package/dist/esm/cloud/v2/routes/index.d.ts.map +1 -1
  293. package/dist/esm/cloud/v2/routes/index.js +37 -1
  294. package/dist/esm/cloud/v2/routes/index.js.map +1 -1
  295. package/dist/esm/cloud/v2/routes/memories.d.ts +21 -2
  296. package/dist/esm/cloud/v2/routes/memories.d.ts.map +1 -1
  297. package/dist/esm/cloud/v2/routes/memories.js +75 -0
  298. package/dist/esm/cloud/v2/routes/memories.js.map +1 -1
  299. package/dist/esm/cloud/v2/routes/recall.d.ts +1 -0
  300. package/dist/esm/cloud/v2/routes/recall.d.ts.map +1 -1
  301. package/dist/esm/cloud/v2/routes/recall.js +5 -1
  302. package/dist/esm/cloud/v2/routes/recall.js.map +1 -1
  303. package/dist/esm/cloud/v2/routes/tenant.d.ts +36 -0
  304. package/dist/esm/cloud/v2/routes/tenant.d.ts.map +1 -0
  305. package/dist/esm/cloud/v2/routes/tenant.js +61 -0
  306. package/dist/esm/cloud/v2/routes/tenant.js.map +1 -0
  307. package/dist/esm/cloud/v2/routes/usage.d.ts +1 -1
  308. package/dist/esm/cloud/v2/routes/usage.d.ts.map +1 -1
  309. package/dist/esm/cloud/v2/routes/verify.d.ts +1 -0
  310. package/dist/esm/cloud/v2/routes/verify.d.ts.map +1 -1
  311. package/dist/esm/cloud/v2/routes/verify.js +5 -1
  312. package/dist/esm/cloud/v2/routes/verify.js.map +1 -1
  313. package/dist/esm/cloud/v2/server.d.ts +9 -3
  314. package/dist/esm/cloud/v2/server.d.ts.map +1 -1
  315. package/dist/esm/cloud/v2/server.js +36 -3
  316. package/dist/esm/cloud/v2/server.js.map +1 -1
  317. package/dist/esm/cloud/v2/usageRecorder.d.ts +19 -0
  318. package/dist/esm/cloud/v2/usageRecorder.d.ts.map +1 -0
  319. package/dist/esm/cloud/v2/usageRecorder.js +37 -0
  320. package/dist/esm/cloud/v2/usageRecorder.js.map +1 -0
  321. package/dist/esm/contracts/api-v2.types.d.ts +92 -2
  322. package/dist/esm/contracts/api-v2.types.d.ts.map +1 -1
  323. package/dist/esm/contracts/store.d.ts +37 -0
  324. package/dist/esm/contracts/store.d.ts.map +1 -1
  325. package/dist/esm/mcp/index.js +8 -2
  326. package/dist/esm/mcp/index.js.map +1 -1
  327. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  328. package/dist/esm/mcp/tools/memory.js +74 -4
  329. package/dist/esm/mcp/tools/memory.js.map +1 -1
  330. package/dist/esm/mcp/tools/misc.d.ts.map +1 -1
  331. package/dist/esm/mcp/tools/misc.js +2 -1
  332. package/dist/esm/mcp/tools/misc.js.map +1 -1
  333. package/dist/esm/mcp/tools/workspace.d.ts.map +1 -1
  334. package/dist/esm/mcp/tools/workspace.js +4 -1
  335. package/dist/esm/mcp/tools/workspace.js.map +1 -1
  336. package/dist/esm/mcp/tools.d.ts +10 -0
  337. package/dist/esm/mcp/tools.d.ts.map +1 -1
  338. package/dist/esm/mcp/tools.js +46 -12
  339. package/dist/esm/mcp/tools.js.map +1 -1
  340. package/dist/esm/proxy/KeyManager.d.ts.map +1 -1
  341. package/dist/esm/proxy/KeyManager.js +5 -0
  342. package/dist/esm/proxy/KeyManager.js.map +1 -1
  343. package/dist/esm/subconscious/CloudBrain.d.ts +77 -0
  344. package/dist/esm/subconscious/CloudBrain.d.ts.map +1 -0
  345. package/dist/esm/subconscious/CloudBrain.js +330 -0
  346. package/dist/esm/subconscious/CloudBrain.js.map +1 -0
  347. package/dist/esm/subconscious/HostRecall.d.ts.map +1 -1
  348. package/dist/esm/subconscious/HostRecall.js +11 -4
  349. package/dist/esm/subconscious/HostRecall.js.map +1 -1
  350. package/dist/esm/subconscious/ProjectIdentity.d.ts +9 -0
  351. package/dist/esm/subconscious/ProjectIdentity.d.ts.map +1 -0
  352. package/dist/esm/subconscious/ProjectIdentity.js +56 -0
  353. package/dist/esm/subconscious/ProjectIdentity.js.map +1 -0
  354. package/dist/esm/subconscious/TeamBrain.d.ts +9 -3
  355. package/dist/esm/subconscious/TeamBrain.d.ts.map +1 -1
  356. package/dist/esm/subconscious/TeamBrain.js +39 -7
  357. package/dist/esm/subconscious/TeamBrain.js.map +1 -1
  358. package/dist/esm/utils/FixCapture.d.ts +7 -5
  359. package/dist/esm/utils/FixCapture.d.ts.map +1 -1
  360. package/dist/esm/utils/FixCapture.js +64 -33
  361. package/dist/esm/utils/FixCapture.js.map +1 -1
  362. package/dist/esm/utils/NoTerminal.d.ts +27 -0
  363. package/dist/esm/utils/NoTerminal.d.ts.map +1 -0
  364. package/dist/esm/utils/NoTerminal.js +33 -0
  365. package/dist/esm/utils/NoTerminal.js.map +1 -0
  366. package/dist/esm/utils/OpenCodeSession.d.ts +70 -0
  367. package/dist/esm/utils/OpenCodeSession.d.ts.map +1 -0
  368. package/dist/esm/utils/OpenCodeSession.js +146 -0
  369. package/dist/esm/utils/OpenCodeSession.js.map +1 -0
  370. package/dist/esm/utils/ProLicense.d.ts.map +1 -1
  371. package/dist/esm/utils/ProLicense.js +11 -3
  372. package/dist/esm/utils/ProLicense.js.map +1 -1
  373. package/dist/esm/utils/SessionCapture.d.ts +31 -7
  374. package/dist/esm/utils/SessionCapture.d.ts.map +1 -1
  375. package/dist/esm/utils/SessionCapture.js +185 -32
  376. package/dist/esm/utils/SessionCapture.js.map +1 -1
  377. package/dist/esm/utils/StopNudge.d.ts +8 -0
  378. package/dist/esm/utils/StopNudge.d.ts.map +1 -0
  379. package/dist/esm/utils/StopNudge.js +86 -0
  380. package/dist/esm/utils/StopNudge.js.map +1 -0
  381. package/dist/esm/utils/TestAutofixInterceptor.d.ts.map +1 -1
  382. package/dist/esm/utils/TestAutofixInterceptor.js +2 -0
  383. package/dist/esm/utils/TestAutofixInterceptor.js.map +1 -1
  384. package/lemma-proxy.cjs +5 -0
  385. package/package.json +2 -1
  386. package/sdks/crewai/dist/ts/src/client.d.ts +5 -1
  387. package/sdks/crewai/dist/ts/src/client.js +8 -0
  388. package/sdks/crewai/dist/ts/src/types.d.ts +32 -1
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PostgresConsoleStore = exports.InMemoryConsoleStore = exports.newToken = exports.hashToken = exports.normalizeEmail = exports.MEMBER_ROLES = void 0;
7
+ /**
8
+ * Lemma Cloud console — members, one-time login links and sessions.
9
+ *
10
+ * Members live in `tenant_seats`. An active email belongs to one tenant only (the login form takes
11
+ * an email and nothing else). Tokens are random and stored as sha256 hashes, never in the clear.
12
+ * A session does not carry the role: `findSession` joins the member row, so a removed member or a
13
+ * changed role is felt on the very next request.
14
+ *
15
+ * `InMemoryConsoleStore` serves tests and the no-database dev path; `PostgresConsoleStore` is production.
16
+ */
17
+ const crypto_1 = __importDefault(require("crypto"));
18
+ exports.MEMBER_ROLES = ['owner', 'admin', 'member'];
19
+ const normalizeEmail = (email) => email.trim().toLowerCase();
20
+ exports.normalizeEmail = normalizeEmail;
21
+ const hashToken = (token) => crypto_1.default.createHash('sha256').update(token).digest('hex');
22
+ exports.hashToken = hashToken;
23
+ /** 256 bits, URL-safe. Only its hash is ever stored. */
24
+ const newToken = () => crypto_1.default.randomBytes(32).toString('base64url');
25
+ exports.newToken = newToken;
26
+ const newMemberId = () => `mem_${crypto_1.default.randomBytes(6).toString('hex')}`;
27
+ class InMemoryConsoleStore {
28
+ constructor(identity) {
29
+ this.identity = identity;
30
+ this.members = [];
31
+ this.loginTokens = new Map();
32
+ this.sessions = new Map();
33
+ }
34
+ async addMember(tenantId, rawEmail, role) {
35
+ const email = (0, exports.normalizeEmail)(rawEmail);
36
+ if (!(await this.identity.getTenant(tenantId)))
37
+ return { ok: false, reason: 'no_tenant' };
38
+ const active = this.members.find((m) => !m.removed && m.email === email);
39
+ if (active)
40
+ return { ok: false, reason: active.tenantId === tenantId ? 'exists' : 'other_tenant' };
41
+ const row = { id: newMemberId(), tenantId, email, role, createdAt: Date.now(), removed: false };
42
+ this.members.push(row);
43
+ return { ok: true, member: toMember(row) };
44
+ }
45
+ async listMembers(tenantId) {
46
+ return this.members.filter((m) => !m.removed && m.tenantId === tenantId).map(toMember);
47
+ }
48
+ async removeMember(tenantId, rawEmail) {
49
+ const email = (0, exports.normalizeEmail)(rawEmail);
50
+ const row = this.members.find((m) => !m.removed && m.tenantId === tenantId && m.email === email);
51
+ if (!row)
52
+ return false;
53
+ row.removed = true;
54
+ for (const [hash, s] of this.sessions)
55
+ if (s.tenantId === tenantId && s.email === email)
56
+ this.sessions.delete(hash);
57
+ return true;
58
+ }
59
+ async findMemberByEmail(rawEmail) {
60
+ const email = (0, exports.normalizeEmail)(rawEmail);
61
+ const row = this.members.find((m) => !m.removed && m.email === email);
62
+ return row ? toMember(row) : null;
63
+ }
64
+ async createLoginToken(i) {
65
+ this.loginTokens.set(i.tokenHash, { tenantId: i.tenantId, email: (0, exports.normalizeEmail)(i.email), expiresAt: i.expiresAt, used: false });
66
+ }
67
+ async consumeLoginToken(tokenHash, now) {
68
+ const t = this.loginTokens.get(tokenHash);
69
+ if (!t || t.used || t.expiresAt <= now)
70
+ return null;
71
+ t.used = true; // synchronous between the check and the write: atomic on one event loop
72
+ return { tenantId: t.tenantId, email: t.email };
73
+ }
74
+ async createSession(i) {
75
+ this.sessions.set(i.tokenHash, { tenantId: i.tenantId, email: (0, exports.normalizeEmail)(i.email), expiresAt: i.expiresAt });
76
+ }
77
+ async findSession(tokenHash, now) {
78
+ const s = this.sessions.get(tokenHash);
79
+ if (!s || s.expiresAt <= now)
80
+ return null;
81
+ const member = this.members.find((m) => !m.removed && m.tenantId === s.tenantId && m.email === s.email);
82
+ return member ? { tenantId: s.tenantId, email: s.email, role: member.role } : null;
83
+ }
84
+ async deleteSession(tokenHash) {
85
+ this.sessions.delete(tokenHash);
86
+ }
87
+ }
88
+ exports.InMemoryConsoleStore = InMemoryConsoleStore;
89
+ const toMember = (r) => ({ id: r.id, tenantId: r.tenantId, email: r.email, role: r.role, createdAt: r.createdAt });
90
+ class PostgresConsoleStore {
91
+ constructor(pool) {
92
+ this.pool = pool;
93
+ }
94
+ async addMember(tenantId, rawEmail, role) {
95
+ const email = (0, exports.normalizeEmail)(rawEmail);
96
+ const existing = await this.findMemberByEmail(email);
97
+ if (existing)
98
+ return { ok: false, reason: existing.tenantId === tenantId ? 'exists' : 'other_tenant' };
99
+ const id = newMemberId();
100
+ try {
101
+ // A removed member of this tenant is brought back instead of colliding with UNIQUE (tenant_id, email).
102
+ const { rows } = await this.pool.query(`INSERT INTO tenant_seats (id, tenant_id, email, role) VALUES ($1, $2, $3, $4)
103
+ ON CONFLICT (tenant_id, email) DO UPDATE SET removed = FALSE, role = EXCLUDED.role
104
+ RETURNING id, tenant_id, email, role, created_at`, [id, tenantId, email, role]);
105
+ return { ok: true, member: rowToMember(rows[0]) };
106
+ }
107
+ catch (err) {
108
+ if (err?.code === '23503')
109
+ return { ok: false, reason: 'no_tenant' };
110
+ if (err?.code === '23505') {
111
+ // Lost a race with another add of the same email.
112
+ const now = await this.findMemberByEmail(email);
113
+ return { ok: false, reason: now && now.tenantId === tenantId ? 'exists' : 'other_tenant' };
114
+ }
115
+ throw err;
116
+ }
117
+ }
118
+ async listMembers(tenantId) {
119
+ 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]);
120
+ return rows.map(rowToMember);
121
+ }
122
+ async removeMember(tenantId, rawEmail) {
123
+ const email = (0, exports.normalizeEmail)(rawEmail);
124
+ 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]);
125
+ await this.pool.query('DELETE FROM console_sessions WHERE tenant_id = $1 AND lower(email) = $2', [tenantId, email]);
126
+ return (rowCount ?? 0) > 0;
127
+ }
128
+ async findMemberByEmail(rawEmail) {
129
+ 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', [(0, exports.normalizeEmail)(rawEmail)]);
130
+ return rows.length ? rowToMember(rows[0]) : null;
131
+ }
132
+ async createLoginToken(i) {
133
+ await this.pool.query('INSERT INTO console_login_tokens (token_hash, tenant_id, email, expires_at) VALUES ($1, $2, $3, $4)', [
134
+ i.tokenHash,
135
+ i.tenantId,
136
+ (0, exports.normalizeEmail)(i.email),
137
+ new Date(i.expiresAt),
138
+ ]);
139
+ }
140
+ async consumeLoginToken(tokenHash, now) {
141
+ // One statement: only the first caller flips used_at, so a link works once even under a race.
142
+ const { rows } = await this.pool.query(`UPDATE console_login_tokens SET used_at = now()
143
+ WHERE token_hash = $1 AND used_at IS NULL AND expires_at > $2
144
+ RETURNING tenant_id, email`, [tokenHash, new Date(now)]);
145
+ // Housekeeping on the way: expired rows are of no use to anyone.
146
+ this.pool.query('DELETE FROM console_login_tokens WHERE expires_at < $1', [new Date(now - 24 * 3600 * 1000)]).catch(() => undefined);
147
+ return rows.length ? { tenantId: rows[0].tenant_id, email: rows[0].email } : null;
148
+ }
149
+ async createSession(i) {
150
+ await this.pool.query('INSERT INTO console_sessions (token_hash, tenant_id, email, expires_at) VALUES ($1, $2, $3, $4)', [
151
+ i.tokenHash,
152
+ i.tenantId,
153
+ (0, exports.normalizeEmail)(i.email),
154
+ new Date(i.expiresAt),
155
+ ]);
156
+ }
157
+ async findSession(tokenHash, now) {
158
+ const { rows } = await this.pool.query(`SELECT s.tenant_id, s.email, m.role
159
+ FROM console_sessions s
160
+ JOIN tenant_seats m ON m.tenant_id = s.tenant_id AND lower(m.email) = s.email AND NOT m.removed
161
+ WHERE s.token_hash = $1 AND s.expires_at > $2`, [tokenHash, new Date(now)]);
162
+ return rows.length ? { tenantId: rows[0].tenant_id, email: rows[0].email, role: rows[0].role } : null;
163
+ }
164
+ async deleteSession(tokenHash) {
165
+ await this.pool.query('DELETE FROM console_sessions WHERE token_hash = $1', [tokenHash]);
166
+ }
167
+ }
168
+ exports.PostgresConsoleStore = PostgresConsoleStore;
169
+ function rowToMember(r) {
170
+ return { id: r.id, tenantId: r.tenant_id, email: r.email, role: r.role, createdAt: new Date(r.created_at).getTime() };
171
+ }
172
+ //# 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,oDAA4B;AAIf,QAAA,YAAY,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAuC3D,MAAM,cAAc,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAAvE,QAAA,cAAc,kBAAyD;AAC7E,MAAM,SAAS,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,gBAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAA/F,QAAA,SAAS,aAAsF;AAC5G,wDAAwD;AACjD,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAAtE,QAAA,QAAQ,YAA8D;AACnF,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC,OAAO,gBAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AAMjF,MAAa,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,IAAA,sBAAc,EAAC,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,IAAA,sBAAc,EAAC,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,IAAA,sBAAc,EAAC,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,IAAA,sBAAc,EAAC,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,IAAA,sBAAc,EAAC,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;AA7DD,oDA6DC;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,MAAa,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,IAAA,sBAAc,EAAC,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,IAAA,sBAAc,EAAC,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,IAAA,sBAAc,EAAC,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,IAAA,sBAAc,EAAC,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,IAAA,sBAAc,EAAC,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;AAhGD,oDAgGC;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';
22
+ import type { IdentityStore } from '../identity/identityStore';
23
+ import type { PlanPolicy } from '../identity/PlanPolicy';
24
+ import type { RateLimiter } from '../identity/RateLimiter';
25
+ import type { UsageLedger } from '../metering';
26
+ import type { StripeApi } from '../billing/stripeApi';
27
+ import { type ConsoleStore } from './ConsoleStore';
28
+ import type { LoginMailer } from './mailer';
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' | 'summarize'>;
39
+ usageLedger?: Pick<UsageLedger, 'computeUsage' | 'computeKeyActivity'> & Partial<Pick<UsageLedger, 'computeDailyActivity'>>;
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;AAQ9B,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,GAAG,WAAW,CAAC,CAAC;IAChD,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,GAAG,oBAAoB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAC5H,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,CA4PvD"}
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loginLink = exports.AttemptLimiter = exports.SESSION_DAYS = exports.LOGIN_LINK_MINUTES = void 0;
7
+ exports.publicBase = publicBase;
8
+ exports.issueLoginLink = issueLoginLink;
9
+ exports.consoleRouter = consoleRouter;
10
+ /**
11
+ * Lemma Cloud console — the web app's server side, mounted at /console.
12
+ *
13
+ * GET /console/ the static app (console/index.html, app.js, styles.css)
14
+ * POST /console/api/login {email} asks for a sign-in link: ALWAYS 202, so it cannot tell who is a member
15
+ * POST /console/api/verify {token} spends the link, starts a session (HttpOnly cookie)
16
+ * POST /console/api/logout
17
+ * GET /console/api/me who you are, your tenant's plan, limits, use and (owner/admin) billing
18
+ * GET /console/api/usage owner/admin: requests and tokens by operation and by dev, this month
19
+ * GET /console/api/team owner/admin: members, keys (never a secret), seats
20
+ * POST /console/api/billing/portal owner/admin: Stripe billing-portal link
21
+ *
22
+ * It is a separate identity from the API keys on purpose: a key belongs to a machine and a tenant, a
23
+ * session belongs to a person. Sessions live in the database, so removing a member ends their access at once.
24
+ *
25
+ * Defences, each cheap: the link travels in the URL FRAGMENT (never reaches a server log or a Referer) and is
26
+ * posted by the page; the cookie is HttpOnly + Secure + SameSite=Lax and scoped to /console; every POST needs
27
+ * a custom header and a same-origin Origin (so a cross-site form cannot act); the CSP allows only our own files.
28
+ */
29
+ const express_1 = __importDefault(require("express"));
30
+ const path_1 = __importDefault(require("path"));
31
+ const zod_1 = require("zod");
32
+ const errors_1 = require("../../contracts/errors");
33
+ const tenant_1 = require("../v2/routes/tenant");
34
+ const ConsoleStore_1 = require("./ConsoleStore");
35
+ exports.LOGIN_LINK_MINUTES = 15;
36
+ exports.SESSION_DAYS = 7;
37
+ const COOKIE = 'lemma_console';
38
+ /** Days on the console's activity chart, today included. */
39
+ const ACTIVITY_DAYS = 30;
40
+ /** Latest memories the console lists. */
41
+ const RECENT_MEMORIES = 12;
42
+ const CSRF_HEADER = 'x-lemma-console';
43
+ /** Counts attempts per key inside a sliding window. Per instance: enough to blunt abuse, not a security boundary. */
44
+ class AttemptLimiter {
45
+ constructor(max, windowMs) {
46
+ this.max = max;
47
+ this.windowMs = windowMs;
48
+ this.hits = new Map();
49
+ }
50
+ allow(key, now) {
51
+ const recent = (this.hits.get(key) ?? []).filter((t) => now - t < this.windowMs);
52
+ if (recent.length >= this.max) {
53
+ this.hits.set(key, recent);
54
+ return false;
55
+ }
56
+ recent.push(now);
57
+ this.hits.set(key, recent);
58
+ if (this.hits.size > 5000)
59
+ for (const [k, v] of this.hits)
60
+ if (!v.some((t) => now - t < this.windowMs))
61
+ this.hits.delete(k);
62
+ return true;
63
+ }
64
+ }
65
+ exports.AttemptLimiter = AttemptLimiter;
66
+ /** The origin the app is served from: configured, else what the proxy in front of us says. */
67
+ function publicBase(req, configured) {
68
+ if (configured)
69
+ return configured.replace(/\/+$/, '');
70
+ const proto = String(req.headers['x-forwarded-proto'] ?? req.protocol).split(',')[0].trim();
71
+ return `${proto}://${req.get('host')}`;
72
+ }
73
+ const loginLink = (base, token) => `${base}/console/#token=${token}`;
74
+ exports.loginLink = loginLink;
75
+ /** Issues a one-time link for an ACTIVE member; null when the email is not one. Shared with the operator route. */
76
+ async function issueLoginLink(store, email, now) {
77
+ const member = await store.findMemberByEmail(email);
78
+ if (!member)
79
+ return null;
80
+ const token = (0, ConsoleStore_1.newToken)();
81
+ const expiresAt = now + exports.LOGIN_LINK_MINUTES * 60000;
82
+ await store.createLoginToken({ tokenHash: (0, ConsoleStore_1.hashToken)(token), tenantId: member.tenantId, email: member.email, expiresAt });
83
+ return { token, email: member.email, expiresAt };
84
+ }
85
+ const LoginSchema = zod_1.z.object({ email: zod_1.z.string().trim().email().max(254) });
86
+ const VerifySchema = zod_1.z.object({ token: zod_1.z.string().min(20).max(200) });
87
+ const fail = (status, code, message) => new errors_1.LemmaApiError({ code, status, message });
88
+ function readCookie(req, name) {
89
+ for (const part of (req.headers.cookie ?? '').split(';')) {
90
+ const i = part.indexOf('=');
91
+ if (i > 0 && part.slice(0, i).trim() === name)
92
+ return part.slice(i + 1).trim();
93
+ }
94
+ return null;
95
+ }
96
+ function consoleRouter(deps) {
97
+ const clock = deps.now ?? Date.now;
98
+ const loginByIp = new AttemptLimiter(20, 60 * 60000);
99
+ const loginByEmail = new AttemptLimiter(5, exports.LOGIN_LINK_MINUTES * 60000);
100
+ const verifyByIp = new AttemptLimiter(30, 15 * 60000);
101
+ const r = express_1.default.Router();
102
+ r.use((_req, res, next) => {
103
+ res.set({
104
+ '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'",
105
+ 'X-Content-Type-Options': 'nosniff',
106
+ 'X-Frame-Options': 'DENY',
107
+ 'Referrer-Policy': 'no-referrer',
108
+ });
109
+ next();
110
+ });
111
+ const api = express_1.default.Router();
112
+ api.use((_req, res, next) => {
113
+ res.set('Cache-Control', 'no-store');
114
+ next();
115
+ });
116
+ // Every state-changing call must come from our own page: a header a cross-site form cannot set, and an Origin that matches.
117
+ api.use((req, _res, next) => {
118
+ if (req.method === 'GET')
119
+ return next();
120
+ if (req.headers[CSRF_HEADER] !== '1')
121
+ return next(fail(403, 'forbidden', 'missing console header'));
122
+ const origin = req.headers.origin;
123
+ if (origin && origin !== publicBase(req, deps.publicBaseUrl))
124
+ return next(fail(403, 'forbidden', 'cross-origin request refused'));
125
+ next();
126
+ });
127
+ const wrap = (fn) => (req, res, next) => {
128
+ fn(req, res).catch(next);
129
+ };
130
+ const setCookie = (res, value, maxAgeSeconds) => res.append('Set-Cookie', `${COOKIE}=${value}; HttpOnly; SameSite=Lax; Path=/console; Max-Age=${maxAgeSeconds}${deps.insecureCookies ? '' : '; Secure'}`);
131
+ const requireSession = async (req, _res, next) => {
132
+ try {
133
+ const token = readCookie(req, COOKIE);
134
+ const session = token ? await deps.consoleStore.findSession((0, ConsoleStore_1.hashToken)(token), clock()) : null;
135
+ if (!session)
136
+ return next(fail(401, 'unauthenticated', 'sign in required'));
137
+ req.session = session;
138
+ next();
139
+ }
140
+ catch (err) {
141
+ next(err);
142
+ }
143
+ };
144
+ const managerOnly = (req, _res, next) => {
145
+ const { role } = req.session;
146
+ if (role === 'owner' || role === 'admin')
147
+ return next();
148
+ next(fail(403, 'forbidden', 'only an owner or admin can see this'));
149
+ };
150
+ api.post('/login', wrap(async (req, res) => {
151
+ const parsed = LoginSchema.safeParse(req.body);
152
+ if (!parsed.success)
153
+ throw fail(400, 'invalid_request', 'a valid email is required');
154
+ const now = clock();
155
+ const email = (0, ConsoleStore_1.normalizeEmail)(parsed.data.email);
156
+ if (!loginByIp.allow(req.ip ?? 'unknown', now) || !loginByEmail.allow(email, now)) {
157
+ 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' } });
158
+ return;
159
+ }
160
+ const issued = await issueLoginLink(deps.consoleStore, email, now);
161
+ if (issued && deps.mailer) {
162
+ const link = (0, exports.loginLink)(publicBase(req, deps.publicBaseUrl), issued.token);
163
+ // Not awaited: an existing and an unknown email take the same time, and a mail outage tells no one anything.
164
+ deps.mailer.sendLoginLink(issued.email, link, exports.LOGIN_LINK_MINUTES).catch((err) => {
165
+ // eslint-disable-next-line no-console
166
+ console.error('[lemma:console] sign-in email failed:', err.message);
167
+ });
168
+ }
169
+ res.status(202).json({ ok: true });
170
+ }));
171
+ api.post('/verify', wrap(async (req, res) => {
172
+ const parsed = VerifySchema.safeParse(req.body);
173
+ if (!parsed.success || !verifyByIp.allow(req.ip ?? 'unknown', clock()))
174
+ throw fail(401, 'unauthenticated', 'this sign-in link is not valid');
175
+ const now = clock();
176
+ const spent = await deps.consoleStore.consumeLoginToken((0, ConsoleStore_1.hashToken)(parsed.data.token), now);
177
+ const member = spent ? await deps.consoleStore.findMemberByEmail(spent.email) : null;
178
+ if (!spent || !member || member.tenantId !== spent.tenantId)
179
+ throw fail(401, 'unauthenticated', 'this sign-in link is not valid or has expired');
180
+ const session = (0, ConsoleStore_1.newToken)();
181
+ await deps.consoleStore.createSession({ tokenHash: (0, ConsoleStore_1.hashToken)(session), tenantId: member.tenantId, email: member.email, expiresAt: now + exports.SESSION_DAYS * 86400000 });
182
+ setCookie(res, session, exports.SESSION_DAYS * 86400);
183
+ res.json({ ok: true });
184
+ }));
185
+ api.post('/logout', wrap(async (req, res) => {
186
+ const token = readCookie(req, COOKIE);
187
+ if (token)
188
+ await deps.consoleStore.deleteSession((0, ConsoleStore_1.hashToken)(token));
189
+ setCookie(res, '', 0);
190
+ res.json({ ok: true });
191
+ }));
192
+ api.get('/me', requireSession, wrap(async (req, res) => {
193
+ const { tenantId, email, role } = req.session;
194
+ const tenant = await deps.identityStore.getTenant(tenantId);
195
+ if (!tenant)
196
+ throw fail(404, 'not_found', 'tenant not found');
197
+ const overview = await (0, tenant_1.buildTenantOverview)(deps, tenant);
198
+ const manager = role === 'owner' || role === 'admin';
199
+ // A plain member sees the plan and the limits; money (status, renewal, late payment) is for owner and admin.
200
+ res.json({ email, role, canManage: manager, tenant: manager ? overview : { ...overview, billing: { status: null, currentPeriodEnd: null, pastDueSince: null } } });
201
+ }));
202
+ api.get('/usage', requireSession, managerOnly, wrap(async (req, res) => {
203
+ const { tenantId } = req.session;
204
+ if (!deps.usageLedger?.computeKeyActivity)
205
+ throw new errors_1.LemmaApiError({ code: 'not_implemented', status: 501, message: 'usage ledger unavailable' });
206
+ const monthStart = new Date(clock());
207
+ const since = Date.UTC(monthStart.getUTCFullYear(), monthStart.getUTCMonth(), 1);
208
+ const [usage, activity, keys] = await Promise.all([
209
+ deps.usageLedger.computeUsage({ tenantId, since }),
210
+ deps.usageLedger.computeKeyActivity({ tenantId, since }),
211
+ deps.identityStore.listKeys(tenantId),
212
+ ]);
213
+ const names = new Map(keys.map((k) => [k.id, k]));
214
+ res.json({
215
+ since,
216
+ metrics: usage.metrics,
217
+ keys: activity.map((a) => ({
218
+ keyId: a.keyId,
219
+ name: names.get(a.keyId)?.name ?? null,
220
+ active: names.get(a.keyId)?.active ?? false,
221
+ requests: a.requests,
222
+ tokens: a.tokens,
223
+ byOperation: a.byOperation,
224
+ })),
225
+ });
226
+ }));
227
+ // The activity chart: requests per UTC day over the last ACTIVITY_DAYS days, and when each key last made one.
228
+ api.get('/activity', requireSession, managerOnly, wrap(async (req, res) => {
229
+ const { tenantId } = req.session;
230
+ if (!deps.usageLedger?.computeDailyActivity)
231
+ throw new errors_1.LemmaApiError({ code: 'not_implemented', status: 501, message: 'usage ledger unavailable' });
232
+ const today = new Date(clock());
233
+ const since = Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()) - (ACTIVITY_DAYS - 1) * 86400000;
234
+ const [activity, byKey, keys] = await Promise.all([
235
+ deps.usageLedger.computeDailyActivity({ tenantId, since, until: clock() }),
236
+ deps.usageLedger.computeKeyActivity({ tenantId, since }),
237
+ deps.identityStore.listKeys(tenantId),
238
+ ]);
239
+ // Every key of the tenant, with its numbers over the same window as the chart (zero when idle).
240
+ const totals = new Map(byKey.map((a) => [a.keyId, a]));
241
+ res.json({
242
+ since,
243
+ days: activity.days,
244
+ keys: keys.map((k) => {
245
+ const a = totals.get(k.id);
246
+ return { keyId: k.id, name: k.name, active: k.active, lastSeenAt: activity.lastSeen[k.id] ?? null, requests: a?.requests ?? 0, tokens: a?.tokens ?? 0, byOperation: a?.byOperation ?? {} };
247
+ }),
248
+ });
249
+ }));
250
+ // The shared Brain at a glance: counts, authors, repos and the latest headlines (never bodies, never hashes).
251
+ api.get('/memories', requireSession, managerOnly, wrap(async (req, res) => {
252
+ const { tenantId } = req.session;
253
+ const now = new Date(clock());
254
+ const since = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1);
255
+ if (!deps.store?.summarize) {
256
+ res.json({ available: false, since, total: await (deps.store ? deps.store.count(tenantId) : Promise.resolve(0)), addedSince: 0, byAuthor: [], byRepo: [], recent: [] });
257
+ return;
258
+ }
259
+ res.json({ available: true, since, ...(await deps.store.summarize(tenantId, { since, recent: RECENT_MEMORIES })) });
260
+ }));
261
+ api.get('/team', requireSession, managerOnly, wrap(async (req, res) => {
262
+ const { tenantId } = req.session;
263
+ const tenant = await deps.identityStore.getTenant(tenantId);
264
+ if (!tenant)
265
+ throw fail(404, 'not_found', 'tenant not found');
266
+ const now = clock();
267
+ const [members, keys] = await Promise.all([deps.consoleStore.listMembers(tenantId), deps.identityStore.listKeys(tenantId)]);
268
+ const used = keys.filter((k) => k.active && (k.expiresAt === null || k.expiresAt > now)).length;
269
+ res.json({
270
+ seats: { used, limit: (deps.policy ? deps.policy.limitsFor(tenant.plan, { founder: tenant.founder }) : { seats: 0 }).seats },
271
+ members: members.map((m) => ({ email: m.email, role: m.role })),
272
+ // A key is shown by its label and state only: the hash and the secret never leave the database.
273
+ keys: keys.map((k) => ({ id: k.id, name: k.name, active: k.active, createdAt: k.createdAt, revokedAt: k.revokedAt })),
274
+ });
275
+ }));
276
+ api.post('/billing/portal', requireSession, managerOnly, wrap(async (req, res) => {
277
+ const { tenantId } = req.session;
278
+ const tenant = await deps.identityStore.getTenant(tenantId);
279
+ if (!tenant)
280
+ throw fail(404, 'not_found', 'tenant not found');
281
+ if (!deps.stripeApi || !tenant.billing.customerId) {
282
+ throw new errors_1.LemmaApiError({ code: 'invalid_request', status: 409, message: 'there is no subscription to manage yet' });
283
+ }
284
+ res.json({ url: (await deps.stripeApi.createPortal(tenant.billing.customerId)).url });
285
+ }));
286
+ r.use('/api', api);
287
+ // The static app. Unknown paths under /console fall back to the page itself (it routes on the fragment).
288
+ const dir = path_1.default.resolve(deps.consoleDir ?? path_1.default.join(process.cwd(), 'console'));
289
+ r.use(express_1.default.static(dir, { index: 'index.html', maxAge: 0, fallthrough: true }));
290
+ r.get('/', (_req, res) => res.sendFile(path_1.default.join(dir, 'index.html')));
291
+ // JSON errors for the API; the app never sees a stack or an HTML error page.
292
+ r.use('/api', (err, _req, res, next) => {
293
+ if (err instanceof errors_1.LemmaApiError) {
294
+ res.status(err.status).json(err.toJSON());
295
+ return;
296
+ }
297
+ next(err);
298
+ });
299
+ return r;
300
+ }
301
+ //# 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"}