@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 @@
1
+ {"version":3,"file":"inputGuard.d.ts","sourceRoot":"","sources":["../../../../src/cloud/v2/inputGuard.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAa/E,6DAA6D;AAC7D,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAkBjD;AAUD,6FAA6F;AAC7F,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAKvG"}
@@ -0,0 +1,63 @@
1
+ import { LemmaApiError } from '../../contracts/errors.js';
2
+ // Detecting control characters is the whole point of this file, so no-control-regex is switched off
3
+ // for the two patterns below, and only for them.
4
+ /** NUL, or a surrogate half with no partner (an invalid UTF-16 string). */
5
+ // eslint-disable-next-line no-control-regex
6
+ const UNSAFE_TEXT = /\u0000|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;
7
+ /** Control characters (C0, DEL) never appear in a real memory id or a key name. */
8
+ // eslint-disable-next-line no-control-regex
9
+ const CONTROL_CHARS = /[\u0000-\u001f\u007f]/;
10
+ /** Longest id any store here generates is far below this. */
11
+ export const MAX_ID_LENGTH = 200;
12
+ export function isUnsafeText(s) {
13
+ return UNSAFE_TEXT.test(s);
14
+ }
15
+ export function hasControlChars(s) {
16
+ return CONTROL_CHARS.test(s);
17
+ }
18
+ export function isSafeId(id) {
19
+ return id.length > 0 && id.length <= MAX_ID_LENGTH && !CONTROL_CHARS.test(id) && !UNSAFE_TEXT.test(id);
20
+ }
21
+ /**
22
+ * Walks the parsed JSON body (keys and string values) and answers 400 on the first
23
+ * unsafe string. Iterative: a hostile deeply nested body must not overflow the stack.
24
+ */
25
+ export function rejectUnsafeBody() {
26
+ return (req, _res, next) => {
27
+ const stack = [req.body];
28
+ while (stack.length > 0) {
29
+ const v = stack.pop();
30
+ if (typeof v === 'string') {
31
+ if (UNSAFE_TEXT.test(v))
32
+ return next(unsafeBodyError());
33
+ }
34
+ else if (Array.isArray(v)) {
35
+ for (const item of v)
36
+ stack.push(item);
37
+ }
38
+ else if (typeof v === 'object' && v !== null) {
39
+ for (const [k, item] of Object.entries(v)) {
40
+ if (UNSAFE_TEXT.test(k))
41
+ return next(unsafeBodyError());
42
+ stack.push(item);
43
+ }
44
+ }
45
+ }
46
+ next();
47
+ };
48
+ }
49
+ function unsafeBodyError() {
50
+ return new LemmaApiError({
51
+ code: 'invalid_request',
52
+ status: 400,
53
+ message: 'request contains a NUL character or invalid Unicode',
54
+ });
55
+ }
56
+ /** app.param('id') handler: an id that cannot exist is the same 404 as one that does not. */
57
+ export function rejectUnsafeIdParam(_req, _res, next, id) {
58
+ if (!isSafeId(id)) {
59
+ return next(new LemmaApiError({ code: 'not_found', status: 404, message: 'memory not found' }));
60
+ }
61
+ next();
62
+ }
63
+ //# sourceMappingURL=inputGuard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputGuard.js","sourceRoot":"","sources":["../../../../src/cloud/v2/inputGuard.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,oGAAoG;AACpG,iDAAiD;AACjD,2EAA2E;AAC3E,4CAA4C;AAC5C,MAAM,WAAW,GAAG,+EAA+E,CAAC;AAEpG,mFAAmF;AACnF,4CAA4C;AAC5C,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAE9C,6DAA6D;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AAEjC,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,CAAS;IACvC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAU;IACjC,OAAO,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,aAAa,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB,EAAE,EAAE;QAC1D,MAAM,KAAK,GAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;YACtB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAC1B,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;oBAAE,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;YAC1D,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5B,KAAK,MAAM,IAAI,IAAI,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzC,CAAC;iBAAM,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC/C,KAAK,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC1C,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;wBAAE,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;oBACxD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,IAAI,aAAa,CAAC;QACvB,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,qDAAqD;KAC/D,CAAC,CAAC;AACL,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,mBAAmB,CAAC,IAAa,EAAE,IAAc,EAAE,IAAkB,EAAE,EAAU;IAC/F,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC,IAAI,aAAa,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { type Router } from 'express';
2
+ import type { IdentityStore } from '../../identity/identityStore.js';
3
+ import { PlanPolicy } from '../../identity/PlanPolicy.js';
4
+ import type { UsageLedger } from '../../metering/index.js';
5
+ import { type StripeApi } from '../../billing/stripeApi.js';
6
+ import { type ConsoleStore } from '../../console/ConsoleStore.js';
7
+ export declare const MIN_ADMIN_TOKEN_LENGTH = 32;
8
+ export interface AdminDeps {
9
+ /** The operator secret. Absent or shorter than MIN_ADMIN_TOKEN_LENGTH => admin routes are not mounted. */
10
+ adminToken?: string;
11
+ identityStore?: IdentityStore;
12
+ policy?: PlanPolicy;
13
+ usageLedger?: Pick<UsageLedger, 'computeUsage' | 'computeKeyActivity'>;
14
+ /** Present only when STRIPE_SECRET_KEY is configured: enables the checkout and portal routes. */
15
+ stripeApi?: Pick<StripeApi, 'createCheckout' | 'createPortal'>;
16
+ /** Present when the console is enabled: turns on the member routes. */
17
+ consoleStore?: ConsoleStore;
18
+ /** Where the console is reachable, for the sign-in links this router hands out. */
19
+ publicBaseUrl?: string;
20
+ }
21
+ /** Returns null when the operator secret is missing or too weak: the caller must not mount anything. */
22
+ export declare function adminRouter(deps: AdminDeps): Router | null;
23
+ export default adminRouter;
24
+ //# sourceMappingURL=admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../../../src/cloud/v2/routes/admin.ts"],"names":[],"mappings":"AA8BA,OAAgB,EAAuE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAIpH,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAY,UAAU,EAAe,MAAM,2BAA2B,CAAC;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI7E,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAIzC,MAAM,WAAW,SAAS;IACxB,0GAA0G;IAC1G,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,GAAG,oBAAoB,CAAC,CAAC;IACvE,iGAAiG;IACjG,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,gBAAgB,GAAG,cAAc,CAAC,CAAC;IAC/D,uEAAuE;IACvE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAoED,wGAAwG;AACxG,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAgR1D;AAED,eAAe,WAAW,CAAC"}
@@ -0,0 +1,337 @@
1
+ /**
2
+ * Lemma API v2 — operator routes: tenants, seats and keys.
3
+ *
4
+ * Not part of the public openapi.yaml contract (customers never call these; the
5
+ * operator does, from the CLI or a dashboard). Guarded by one operator secret,
6
+ * `LEMMA_ADMIN_TOKEN`, which is NOT an API key and resolves to no tenant. With the
7
+ * secret unset the router is simply not mounted, so there is nothing to probe.
8
+ *
9
+ * POST /v2/admin/tenants {id, name?, plan?, founder?} create a company
10
+ * GET /v2/admin/tenants/:id plan, seats used/limit, keys
11
+ * PATCH /v2/admin/tenants/:id {plan} change plan (never below seats in use)
12
+ * POST /v2/admin/tenants/:id/founder {founder} mark a founder team (keeps the founder limits)
13
+ * POST /v2/admin/tenants/:id/keys {name} issue a key (shown once)
14
+ * DELETE /v2/admin/tenants/:id/keys/:keyId revoke (the dev left)
15
+ * GET /v2/admin/tenants/:id/usage?since=<epoch ms> usage by operation and by dev
16
+ * POST /v2/admin/tenants/:id/checkout {plan, interval, founder?, email?} Stripe Checkout link to send the customer
17
+ * POST /v2/admin/tenants/:id/portal Stripe billing-portal link for a paying tenant
18
+ *
19
+ * POST /v2/admin/tenants/:id/members {email, role?} let a person sign in to the console (owner | admin | member)
20
+ * GET /v2/admin/tenants/:id/members who can sign in
21
+ * DELETE /v2/admin/tenants/:id/members/:email remove them (their sessions end at once)
22
+ * POST /v2/admin/tenants/:id/members/:email/login-link a one-time sign-in link, to hand over by hand
23
+ *
24
+ * The checkout and portal routes exist only when STRIPE_SECRET_KEY is set; the member routes only with a console store. The checkout link carries the tenant id, so paying
25
+ * is what links the Stripe customer to the tenant; the webhook then sets the plan.
26
+ *
27
+ * A seat is one active, unexpired key. Issuing past the plan's seat ceiling is a 429
28
+ * `quota_exceeded`; the check and the insert are atomic in the store.
29
+ */
30
+ import crypto from 'crypto';
31
+ import express from 'express';
32
+ import { z } from 'zod';
33
+ import { LemmaApiError } from '../../../contracts/errors.js';
34
+ import { generateApiKey, KEY_PREFIX_LIVE } from '../../identity/ApiKey.js';
35
+ import { PLAN_IDS, PlanPolicy } from '../../identity/PlanPolicy.js';
36
+ import { hasControlChars, rejectUnsafeBody } from '../inputGuard.js';
37
+ import { SELLABLE_PLANS } from '../../billing/stripeApi.js';
38
+ import { MEMBER_ROLES } from '../../console/ConsoleStore.js';
39
+ import { issueLoginLink, loginLink, publicBase } from '../../console/consoleRouter.js';
40
+ import { zodToApiError } from './memories.js';
41
+ export const MIN_ADMIN_TOKEN_LENGTH = 32;
42
+ const TENANT_ID = /^[a-z0-9][a-z0-9_-]{1,62}$/;
43
+ const KEY_ID = /^key_[0-9a-f]{12}$/;
44
+ const PlanSchema = z.enum(PLAN_IDS);
45
+ const CreateTenantSchema = z.object({
46
+ id: z.string().regex(TENANT_ID, 'id must be 2-63 chars: a-z, 0-9, "_" or "-", starting with a letter or digit'),
47
+ name: z.string().max(200).optional(),
48
+ plan: PlanSchema.optional(),
49
+ /** A founder team created by hand: it keeps the founder limits (PlanPolicy FOUNDER_LIMITS). */
50
+ founder: z.boolean().optional(),
51
+ });
52
+ const FounderSchema = z.object({ founder: z.boolean() }).strict();
53
+ const PatchTenantSchema = z.object({ plan: PlanSchema });
54
+ const AddMemberSchema = z.object({
55
+ email: z.string().trim().email().max(254),
56
+ role: z.enum(MEMBER_ROLES).optional(),
57
+ });
58
+ const CheckoutSchema = z.object({
59
+ plan: z.enum(SELLABLE_PLANS),
60
+ interval: z.enum(['month', 'year']),
61
+ /** The founder discount: first teams only, monthly billing only (a coupon on a yearly price would take 20 or 70 off once). */
62
+ founder: z.boolean().optional(),
63
+ email: z.string().trim().email().max(254).optional(),
64
+ });
65
+ const CreateKeySchema = z.object({
66
+ name: z
67
+ .string()
68
+ .trim()
69
+ .min(1)
70
+ .max(100)
71
+ .refine((n) => !hasControlChars(n), 'name must not contain control characters'),
72
+ });
73
+ const sha = (s) => crypto.createHash('sha256').update(s).digest();
74
+ function bearer(req) {
75
+ const m = /^Bearer\s+(.+)$/i.exec((req.headers.authorization ?? '').trim());
76
+ return m ? m[1].trim() : null;
77
+ }
78
+ function requireAdmin(token) {
79
+ const expected = sha(token);
80
+ return (req, res, next) => {
81
+ const given = bearer(req);
82
+ // Hash both sides first so the compare is constant-time regardless of the given length.
83
+ if (given && crypto.timingSafeEqual(sha(given), expected))
84
+ return next();
85
+ res.status(401).set('WWW-Authenticate', 'Bearer').json(new LemmaApiError({ code: 'unauthenticated', status: 401, message: 'missing or invalid operator token' }).toJSON());
86
+ };
87
+ }
88
+ const notFound = (what) => new LemmaApiError({ code: 'not_found', status: 404, message: `${what} not found` });
89
+ const publicKey = (k) => ({
90
+ id: k.id,
91
+ name: k.name,
92
+ prefix: k.prefix,
93
+ active: k.active,
94
+ createdAt: k.createdAt,
95
+ revokedAt: k.revokedAt,
96
+ });
97
+ const wrap = (fn) => (req, res, next) => {
98
+ fn(req, res).catch(next);
99
+ };
100
+ /** Returns null when the operator secret is missing or too weak: the caller must not mount anything. */
101
+ export function adminRouter(deps) {
102
+ const { adminToken, identityStore: store } = deps;
103
+ if (!adminToken || adminToken.length < MIN_ADMIN_TOKEN_LENGTH || !store)
104
+ return null;
105
+ const policy = deps.policy ?? new PlanPolicy();
106
+ const r = express.Router();
107
+ r.use(requireAdmin(adminToken));
108
+ r.use(rejectUnsafeBody());
109
+ const tenantParam = (req) => {
110
+ const id = req.params.tenantId;
111
+ if (!TENANT_ID.test(id))
112
+ throw notFound('tenant');
113
+ return id;
114
+ };
115
+ const tenantView = async (id) => {
116
+ const tenant = await store.getTenant(id);
117
+ if (!tenant)
118
+ throw notFound('tenant');
119
+ const keys = await store.listKeys(id);
120
+ const now = Date.now();
121
+ const used = keys.filter((k) => k.active && (k.expiresAt === null || k.expiresAt > now)).length;
122
+ return {
123
+ id: tenant.id,
124
+ name: tenant.name,
125
+ plan: tenant.plan,
126
+ founder: tenant.founder,
127
+ createdAt: tenant.createdAt,
128
+ seats: { used, limit: policy.limitsFor(tenant.plan, { founder: tenant.founder }).seats },
129
+ keys: keys.map(publicKey),
130
+ };
131
+ };
132
+ r.post('/tenants', wrap(async (req, res) => {
133
+ const parsed = CreateTenantSchema.safeParse(req.body);
134
+ if (!parsed.success)
135
+ throw zodToApiError(parsed.error);
136
+ const { id, name, plan, founder } = parsed.data;
137
+ const created = await store.createTenant({ id, name: name ?? id, plan: (plan ?? 'free'), founder: founder === true });
138
+ if (!created)
139
+ throw new LemmaApiError({ code: 'invalid_request', status: 409, message: 'tenant already exists', field: 'id' });
140
+ res.status(201).json({ id: created.id, name: created.name, plan: created.plan, founder: created.founder });
141
+ }));
142
+ r.get('/tenants/:tenantId', wrap(async (req, res) => {
143
+ res.json(await tenantView(tenantParam(req)));
144
+ }));
145
+ r.patch('/tenants/:tenantId', wrap(async (req, res) => {
146
+ const id = tenantParam(req);
147
+ const parsed = PatchTenantSchema.safeParse(req.body);
148
+ if (!parsed.success)
149
+ throw zodToApiError(parsed.error);
150
+ const current = await tenantView(id);
151
+ const newSeats = policy.limitsFor(parsed.data.plan).seats;
152
+ if (current.seats.used > newSeats) {
153
+ throw new LemmaApiError({
154
+ code: 'invalid_request',
155
+ status: 409,
156
+ message: `plan "${parsed.data.plan}" allows ${newSeats} seats but ${current.seats.used} are in use: revoke keys first`,
157
+ field: 'plan',
158
+ });
159
+ }
160
+ await store.setTenantPlan(id, parsed.data.plan);
161
+ res.json(await tenantView(id));
162
+ }));
163
+ // Mark (or, to correct a mistake, unmark) a founder. Billing marks paid founder checkouts by itself.
164
+ r.post('/tenants/:tenantId/founder', wrap(async (req, res) => {
165
+ const id = tenantParam(req);
166
+ const parsed = FounderSchema.safeParse(req.body);
167
+ if (!parsed.success)
168
+ throw zodToApiError(parsed.error);
169
+ if (!(await store.setTenantFounder(id, parsed.data.founder)))
170
+ throw notFound('tenant');
171
+ res.json(await tenantView(id));
172
+ }));
173
+ r.post('/tenants/:tenantId/keys', wrap(async (req, res) => {
174
+ const id = tenantParam(req);
175
+ const parsed = CreateKeySchema.safeParse(req.body);
176
+ if (!parsed.success)
177
+ throw zodToApiError(parsed.error);
178
+ const tenant = await store.getTenant(id);
179
+ if (!tenant)
180
+ throw notFound('tenant');
181
+ const generated = generateApiKey(KEY_PREFIX_LIVE);
182
+ const result = await store.createKeyWithinSeats({ tenantId: id, name: parsed.data.name, plan: tenant.plan, prefix: KEY_PREFIX_LIVE, hash: generated.hash }, policy.limitsFor(tenant.plan).seats);
183
+ if (!result.ok) {
184
+ if (result.reason === 'no_tenant')
185
+ throw notFound('tenant');
186
+ if (result.reason === 'duplicate_name') {
187
+ throw new LemmaApiError({ code: 'invalid_request', status: 409, message: 'an active key with that name already exists', field: 'name' });
188
+ }
189
+ throw new LemmaApiError({
190
+ code: 'quota_exceeded',
191
+ status: 429,
192
+ message: `seat limit reached: ${result.used}/${result.seats} on plan "${tenant.plan}"`,
193
+ });
194
+ }
195
+ // The only response that ever carries the plaintext key.
196
+ res.status(201).json({ id: result.key.id, name: result.key.name, prefix: result.key.prefix, key: generated.key });
197
+ }));
198
+ r.delete('/tenants/:tenantId/keys/:keyId', wrap(async (req, res) => {
199
+ const id = tenantParam(req);
200
+ const keyId = req.params.keyId;
201
+ if (!KEY_ID.test(keyId))
202
+ throw notFound('key');
203
+ // The key must belong to THIS tenant: an id from another tenant is the same 404.
204
+ const keys = await store.listKeys(id);
205
+ if (!keys.some((k) => k.id === keyId))
206
+ throw notFound('key');
207
+ await store.revokeKey(keyId);
208
+ res.json({ revoked: [keyId] });
209
+ }));
210
+ r.get('/tenants/:tenantId/usage', wrap(async (req, res) => {
211
+ const id = tenantParam(req);
212
+ if (!(await store.getTenant(id)))
213
+ throw notFound('tenant');
214
+ const ledger = deps.usageLedger;
215
+ if (!ledger || !ledger.computeKeyActivity)
216
+ throw new LemmaApiError({ code: 'not_implemented', status: 501, message: 'usage ledger unavailable' });
217
+ const rawSince = req.query.since;
218
+ let since;
219
+ if (rawSince !== undefined) {
220
+ // Digits only: Number('') is 0 and Number(' 5 ') is 5, neither of which is a timestamp anyone meant.
221
+ since = typeof rawSince === 'string' && /^\d{1,16}$/.test(rawSince) ? Number(rawSince) : NaN;
222
+ if (!Number.isSafeInteger(since)) {
223
+ throw new LemmaApiError({ code: 'invalid_request', status: 400, message: 'since must be a non-negative integer (epoch ms)', field: 'since' });
224
+ }
225
+ }
226
+ const [usage, activity, keys] = await Promise.all([
227
+ ledger.computeUsage({ tenantId: id, since }),
228
+ ledger.computeKeyActivity({ tenantId: id, since }),
229
+ store.listKeys(id),
230
+ ]);
231
+ const names = new Map(keys.map((k) => [k.id, k.name]));
232
+ res.json({
233
+ tenantId: id,
234
+ since: since ?? null,
235
+ metrics: usage.metrics,
236
+ excludedEvents: usage.excludedEvents,
237
+ // One row per key that made calls, with the dev's name and whether the key is still live.
238
+ keys: activity.map((a) => ({
239
+ keyId: a.keyId,
240
+ name: names.get(a.keyId) ?? null,
241
+ active: keys.find((k) => k.id === a.keyId)?.active ?? false,
242
+ requests: a.requests,
243
+ tokens: a.tokens,
244
+ byOperation: a.byOperation,
245
+ })),
246
+ });
247
+ }));
248
+ if (deps.stripeApi) {
249
+ const stripeApi = deps.stripeApi;
250
+ // A subscription in any of these states already pays for the tenant: a second one would bill twice.
251
+ const LIVE_SUBSCRIPTION = new Set(['active', 'trialing', 'past_due', 'unpaid', 'incomplete']);
252
+ r.post('/tenants/:tenantId/checkout', wrap(async (req, res) => {
253
+ const id = tenantParam(req);
254
+ const parsed = CheckoutSchema.safeParse(req.body);
255
+ if (!parsed.success)
256
+ throw zodToApiError(parsed.error);
257
+ const { plan, interval, founder = false, email } = parsed.data;
258
+ if (founder && interval !== 'month') {
259
+ throw new LemmaApiError({ code: 'invalid_request', status: 400, message: 'the founder price is for monthly billing only', field: 'founder' });
260
+ }
261
+ const tenant = await store.getTenant(id);
262
+ if (!tenant)
263
+ throw notFound('tenant');
264
+ if (tenant.plan === 'internal') {
265
+ throw new LemmaApiError({ code: 'invalid_request', status: 409, message: 'an internal tenant is not sold through Stripe' });
266
+ }
267
+ const status = tenant.billing.status;
268
+ if (tenant.billing.subscriptionId && status && LIVE_SUBSCRIPTION.has(status)) {
269
+ throw new LemmaApiError({
270
+ code: 'invalid_request',
271
+ status: 409,
272
+ message: `this tenant already has a subscription (${status}): change it in the billing portal instead`,
273
+ });
274
+ }
275
+ const link = await stripeApi.createCheckout({ tenantId: id, plan, interval, founder, existingCustomerId: tenant.billing.customerId, email });
276
+ res.status(201).json({ tenantId: id, plan, interval, founder, trialDays: 14, url: link.url, expiresAt: link.expiresAt });
277
+ }));
278
+ r.post('/tenants/:tenantId/portal', wrap(async (req, res) => {
279
+ const id = tenantParam(req);
280
+ const tenant = await store.getTenant(id);
281
+ if (!tenant)
282
+ throw notFound('tenant');
283
+ if (!tenant.billing.customerId) {
284
+ throw new LemmaApiError({ code: 'invalid_request', status: 409, message: 'this tenant has no Stripe customer yet: send it a checkout link first' });
285
+ }
286
+ res.json({ tenantId: id, url: (await stripeApi.createPortal(tenant.billing.customerId)).url });
287
+ }));
288
+ }
289
+ if (deps.consoleStore) {
290
+ const consoleStore = deps.consoleStore;
291
+ r.post('/tenants/:tenantId/members', wrap(async (req, res) => {
292
+ const id = tenantParam(req);
293
+ const parsed = AddMemberSchema.safeParse(req.body);
294
+ if (!parsed.success)
295
+ throw zodToApiError(parsed.error);
296
+ const added = await consoleStore.addMember(id, parsed.data.email, parsed.data.role ?? 'member');
297
+ if (!added.ok) {
298
+ if (added.reason === 'no_tenant')
299
+ throw notFound('tenant');
300
+ throw new LemmaApiError({
301
+ code: 'invalid_request',
302
+ status: 409,
303
+ message: added.reason === 'exists' ? 'that person is already a member of this tenant' : 'that email already belongs to another tenant',
304
+ field: 'email',
305
+ });
306
+ }
307
+ res.status(201).json({ id: added.member.id, email: added.member.email, role: added.member.role });
308
+ }));
309
+ r.get('/tenants/:tenantId/members', wrap(async (req, res) => {
310
+ const id = tenantParam(req);
311
+ if (!(await store.getTenant(id)))
312
+ throw notFound('tenant');
313
+ res.json({ members: (await consoleStore.listMembers(id)).map((m) => ({ email: m.email, role: m.role })) });
314
+ }));
315
+ r.delete('/tenants/:tenantId/members/:email', wrap(async (req, res) => {
316
+ const id = tenantParam(req);
317
+ if (!(await consoleStore.removeMember(id, req.params.email)))
318
+ throw notFound('member');
319
+ res.json({ removed: req.params.email.trim().toLowerCase() });
320
+ }));
321
+ r.post('/tenants/:tenantId/members/:email/login-link', wrap(async (req, res) => {
322
+ const id = tenantParam(req);
323
+ const member = await consoleStore.findMemberByEmail(req.params.email);
324
+ // Another tenant's member is the same 404 as a stranger: this route never confirms who belongs where.
325
+ if (!member || member.tenantId !== id)
326
+ throw notFound('member');
327
+ const issued = await issueLoginLink(consoleStore, member.email, Date.now());
328
+ if (!issued)
329
+ throw notFound('member');
330
+ res.status(201).json({ email: issued.email, url: loginLink(publicBase(req, deps.publicBaseUrl), issued.token), expiresAt: issued.expiresAt });
331
+ }));
332
+ }
333
+ r.use((_req, _res, next) => next(notFound('route')));
334
+ return r;
335
+ }
336
+ export default adminRouter;
337
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../../../src/cloud/v2/routes/admin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Lemma API v2 — GET /v2/entitlement
3
+ *
4
+ * What the presented key may do on the client, beyond the API itself: today, whether a seat on this
5
+ * plan also unlocks the local Pro tools. The answer comes from the tenant's plan (PLAN_INCLUDES_PRO),
6
+ * never from anything the caller sends. A revoked or expired key never gets here: authenticateV2
7
+ * answers it 401 first, which is how a client learns a seat was taken away.
8
+ */
9
+ import type { RequestHandler } from 'express';
10
+ /** GET /v2/entitlement */
11
+ export declare function entitlementHandler(): RequestHandler;
12
+ export default entitlementHandler;
13
+ //# sourceMappingURL=entitlement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlement.d.ts","sourceRoot":"","sources":["../../../../../src/cloud/v2/routes/entitlement.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK9C,0BAA0B;AAC1B,wBAAgB,kBAAkB,IAAI,cAAc,CAenD;AAED,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { PLAN_INCLUDES_PRO } from '../../identity/PlanPolicy.js';
2
+ /** GET /v2/entitlement */
3
+ export function entitlementHandler() {
4
+ return (req, res, next) => {
5
+ try {
6
+ const { tenant } = req;
7
+ const body = {
8
+ tenantId: tenant.id,
9
+ plan: tenant.plan,
10
+ includesPro: PLAN_INCLUDES_PRO[tenant.plan] === true,
11
+ ...(tenant.keyName ? { keyName: tenant.keyName } : {}),
12
+ };
13
+ res.json(body);
14
+ }
15
+ catch (err) {
16
+ next(err);
17
+ }
18
+ };
19
+ }
20
+ export default entitlementHandler;
21
+ //# sourceMappingURL=entitlement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlement.js","sourceRoot":"","sources":["../../../../../src/cloud/v2/routes/entitlement.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,0BAA0B;AAC1B,MAAM,UAAU,kBAAkB;IAChC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,GAA2B,CAAC;YAC/C,MAAM,IAAI,GAAwB;gBAChC,QAAQ,EAAE,MAAM,CAAC,EAAE;gBACnB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,WAAW,EAAE,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI;gBACpD,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACvD,CAAC;YACF,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,eAAe,kBAAkB,CAAC"}
@@ -18,7 +18,20 @@ import { type MemoriesDeps } from './memories.js';
18
18
  import { type RecallDeps } from './recall.js';
19
19
  import { type VerifyDeps } from './verify.js';
20
20
  import { type UsageDeps } from './usage.js';
21
- export type MountDeps = AuthenticateV2Deps & MemoriesDeps & RecallDeps & VerifyDeps & UsageDeps;
21
+ import { type AdminDeps } from './admin.js';
22
+ import type { StripeBillingConfig } from '../../billing/stripeWebhook.js';
23
+ import type { ConsoleStore } from '../../console/ConsoleStore.js';
24
+ import type { LoginMailer } from '../../console/mailer.js';
25
+ export type MountDeps = AuthenticateV2Deps & MemoriesDeps & RecallDeps & VerifyDeps & UsageDeps & AdminDeps & {
26
+ billing?: StripeBillingConfig;
27
+ /** The web console: members, sign-in links and sessions. Absent => /console and the member routes are not mounted. */
28
+ consoleStore?: ConsoleStore;
29
+ loginMailer?: LoginMailer;
30
+ /** Where the console is reachable (CLOUD_PUBLIC_URL), for links in emails. */
31
+ publicBaseUrl?: string;
32
+ consoleDir?: string;
33
+ insecureCookies?: boolean;
34
+ };
22
35
  export declare function mountRoutes(app: Express, deps: MountDeps): void;
23
36
  export default mountRoutes;
24
37
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cloud/v2/routes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxF,OAAO,EAA4C,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAIvD,MAAM,MAAM,SAAS,GAAG,kBAAkB,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;AAEhG,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAuB/D;AAED,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cloud/v2/routes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxF,OAAO,EAA8D,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3G,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAMvD,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,MAAM,SAAS,GAAG,kBAAkB,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG;IAC1G,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,sHAAsH;IACtH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEJ,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAyD/D;AAED,eAAe,WAAW,CAAC"}
@@ -1,10 +1,16 @@
1
1
  import { authenticateV2 } from '../../identity/authenticateV2.js';
2
- import { createMemoryHandler, forgetMemoryHandler } from './memories.js';
2
+ import { createMemoryHandler, forgetMemoryHandler, getMemoryHandler } from './memories.js';
3
3
  import { recallHandler } from './recall.js';
4
4
  import { verifyHandler } from './verify.js';
5
5
  import { usageHandler } from './usage.js';
6
+ import { entitlementHandler } from './entitlement.js';
7
+ import { tenantOverviewHandler } from './tenant.js';
6
8
  import { scrubRouter } from './scrub.js';
7
9
  import { LemmaApiError } from '../../../contracts/errors.js';
10
+ import { rejectUnsafeBody, rejectUnsafeIdParam } from '../inputGuard.js';
11
+ import { adminRouter } from './admin.js';
12
+ import { usageRecorder } from '../usageRecorder.js';
13
+ import { consoleRouter } from '../../console/consoleRouter.js';
8
14
  export function mountRoutes(app, deps) {
9
15
  // Public: no tenant, no auth (Lane F, stateless).
10
16
  const scrub = scrubRouter();
@@ -19,14 +25,44 @@ export function mountRoutes(app, deps) {
19
25
  next(err);
20
26
  }
21
27
  });
28
+ // Operator routes: their own secret, mounted only when LEMMA_ADMIN_TOKEN is strong enough.
29
+ const admin = adminRouter({ adminToken: deps.adminToken, identityStore: deps.identityStore, policy: deps.policy, usageLedger: deps.usageLedger, stripeApi: deps.stripeApi, consoleStore: deps.consoleStore, publicBaseUrl: deps.publicBaseUrl });
30
+ if (admin)
31
+ app.use('/v2/admin', admin);
32
+ // The web console has its own identity (a person's session, not an API key), so it sits outside the /v2 key auth.
33
+ if (deps.consoleStore && deps.identityStore) {
34
+ app.use('/console', consoleRouter({
35
+ consoleStore: deps.consoleStore,
36
+ identityStore: deps.identityStore,
37
+ policy: deps.policy,
38
+ store: deps.store,
39
+ rateLimiter: deps.rateLimiter,
40
+ rateLimitWindowMs: deps.rateLimitWindowMs,
41
+ usageLedger: deps.usageLedger,
42
+ stripeApi: deps.stripeApi,
43
+ mailer: deps.loginMailer,
44
+ publicBaseUrl: deps.publicBaseUrl,
45
+ consoleDir: deps.consoleDir,
46
+ insecureCookies: deps.insecureCookies,
47
+ now: deps.now,
48
+ }));
49
+ }
22
50
  // Everything below requires a valid tenant.
23
51
  const auth = authenticateV2(deps);
24
52
  app.use('/v2', auth);
53
+ // After auth, so an unauthenticated probe still gets 401. /v2/scrub is mounted above
54
+ // and stays untouched: it is stateless and never reaches a store.
55
+ app.use('/v2', rejectUnsafeBody());
56
+ app.use('/v2', usageRecorder(deps.usageLedger));
57
+ app.param('id', rejectUnsafeIdParam);
25
58
  app.post('/v2/memories', createMemoryHandler(deps));
59
+ app.get('/v2/memories/:id', getMemoryHandler(deps));
26
60
  app.delete('/v2/memories/:id', forgetMemoryHandler(deps));
27
61
  app.post('/v2/recall', recallHandler(deps));
28
62
  app.post('/v2/verify', verifyHandler(deps));
29
63
  app.get('/v2/usage', usageHandler(deps));
64
+ app.get('/v2/entitlement', entitlementHandler());
65
+ app.get('/v2/tenant', tenantOverviewHandler(deps));
30
66
  }
31
67
  export default mountRoutes;
32
68
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/cloud/v2/routes/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,cAAc,EAA2B,MAAM,+BAA+B,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAqB,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,aAAa,EAAmB,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAmB,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAkB,MAAM,SAAS,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAI1D,MAAM,UAAU,WAAW,CAAC,GAAY,EAAE,IAAe;IACvD,kDAAkD;IAClD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC3B,MAAM,IAAI,aAAa,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC,CAAC;YACnH,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,4CAA4C;IAC5C,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAClC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAErB,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;IACpD,GAAG,CAAC,MAAM,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/cloud/v2/routes/index.ts"],"names":[],"mappings":"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"}