@nxuss/lemma 1.43.0 → 1.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/README.md +1 -1
  2. package/bin/brain-ingest.js +18 -0
  3. package/bin/cloud.js +228 -0
  4. package/dist/cjs/cli/hostHooks.d.ts +6 -0
  5. package/dist/cjs/cli/hostHooks.d.ts.map +1 -1
  6. package/dist/cjs/cli/hostHooks.js +13 -3
  7. package/dist/cjs/cli/hostHooks.js.map +1 -1
  8. package/dist/cjs/cloud/CloudBrainClient.d.ts +52 -0
  9. package/dist/cjs/cloud/CloudBrainClient.d.ts.map +1 -0
  10. package/dist/cjs/cloud/CloudBrainClient.js +161 -0
  11. package/dist/cjs/cloud/CloudBrainClient.js.map +1 -0
  12. package/dist/cjs/cloud/CloudConfig.d.ts +41 -0
  13. package/dist/cjs/cloud/CloudConfig.d.ts.map +1 -0
  14. package/dist/cjs/cloud/CloudConfig.js +133 -0
  15. package/dist/cjs/cloud/CloudConfig.js.map +1 -0
  16. package/dist/cjs/cloud/CloudEntitlement.d.ts +55 -0
  17. package/dist/cjs/cloud/CloudEntitlement.d.ts.map +1 -0
  18. package/dist/cjs/cloud/CloudEntitlement.js +174 -0
  19. package/dist/cjs/cloud/CloudEntitlement.js.map +1 -0
  20. package/dist/cjs/cloud/billing/stripeApi.d.ts +43 -0
  21. package/dist/cjs/cloud/billing/stripeApi.d.ts.map +1 -0
  22. package/dist/cjs/cloud/billing/stripeApi.js +111 -0
  23. package/dist/cjs/cloud/billing/stripeApi.js.map +1 -0
  24. package/dist/cjs/cloud/billing/stripeWebhook.d.ts +35 -0
  25. package/dist/cjs/cloud/billing/stripeWebhook.d.ts.map +1 -0
  26. package/dist/cjs/cloud/billing/stripeWebhook.js +185 -0
  27. package/dist/cjs/cloud/billing/stripeWebhook.js.map +1 -0
  28. package/dist/cjs/cloud/console/ConsoleStore.d.ts +111 -0
  29. package/dist/cjs/cloud/console/ConsoleStore.d.ts.map +1 -0
  30. package/dist/cjs/cloud/console/ConsoleStore.js +172 -0
  31. package/dist/cjs/cloud/console/ConsoleStore.js.map +1 -0
  32. package/dist/cjs/cloud/console/consoleRouter.d.ts +68 -0
  33. package/dist/cjs/cloud/console/consoleRouter.d.ts.map +1 -0
  34. package/dist/cjs/cloud/console/consoleRouter.js +263 -0
  35. package/dist/cjs/cloud/console/consoleRouter.js.map +1 -0
  36. package/dist/cjs/cloud/console/mailer.d.ts +22 -0
  37. package/dist/cjs/cloud/console/mailer.d.ts.map +1 -0
  38. package/dist/cjs/cloud/console/mailer.js +35 -0
  39. package/dist/cjs/cloud/console/mailer.js.map +1 -0
  40. package/dist/cjs/cloud/identity/PlanPolicy.d.ts +16 -1
  41. package/dist/cjs/cloud/identity/PlanPolicy.d.ts.map +1 -1
  42. package/dist/cjs/cloud/identity/PlanPolicy.js +47 -7
  43. package/dist/cjs/cloud/identity/PlanPolicy.js.map +1 -1
  44. package/dist/cjs/cloud/identity/RateLimiter.d.ts +21 -1
  45. package/dist/cjs/cloud/identity/RateLimiter.d.ts.map +1 -1
  46. package/dist/cjs/cloud/identity/RateLimiter.js +59 -2
  47. package/dist/cjs/cloud/identity/RateLimiter.js.map +1 -1
  48. package/dist/cjs/cloud/identity/TenantResolver.d.ts +4 -1
  49. package/dist/cjs/cloud/identity/TenantResolver.d.ts.map +1 -1
  50. package/dist/cjs/cloud/identity/TenantResolver.js +1 -1
  51. package/dist/cjs/cloud/identity/TenantResolver.js.map +1 -1
  52. package/dist/cjs/cloud/identity/authenticateV2.d.ts.map +1 -1
  53. package/dist/cjs/cloud/identity/authenticateV2.js +7 -4
  54. package/dist/cjs/cloud/identity/authenticateV2.js.map +1 -1
  55. package/dist/cjs/cloud/identity/identityStore.d.ts +85 -10
  56. package/dist/cjs/cloud/identity/identityStore.d.ts.map +1 -1
  57. package/dist/cjs/cloud/identity/identityStore.js +184 -2
  58. package/dist/cjs/cloud/identity/identityStore.js.map +1 -1
  59. package/dist/cjs/cloud/metering/PostgresLedgerStore.d.ts +16 -0
  60. package/dist/cjs/cloud/metering/PostgresLedgerStore.d.ts.map +1 -0
  61. package/dist/cjs/cloud/metering/PostgresLedgerStore.js +44 -0
  62. package/dist/cjs/cloud/metering/PostgresLedgerStore.js.map +1 -0
  63. package/dist/cjs/cloud/metering/UsageLedger.d.ts +37 -0
  64. package/dist/cjs/cloud/metering/UsageLedger.d.ts.map +1 -1
  65. package/dist/cjs/cloud/metering/UsageLedger.js +80 -17
  66. package/dist/cjs/cloud/metering/UsageLedger.js.map +1 -1
  67. package/dist/cjs/cloud/metering/index.d.ts +1 -0
  68. package/dist/cjs/cloud/metering/index.d.ts.map +1 -1
  69. package/dist/cjs/cloud/metering/index.js +1 -0
  70. package/dist/cjs/cloud/metering/index.js.map +1 -1
  71. package/dist/cjs/cloud/store/FileBrainStore.d.ts +1 -0
  72. package/dist/cjs/cloud/store/FileBrainStore.d.ts.map +1 -1
  73. package/dist/cjs/cloud/store/FileBrainStore.js +3 -0
  74. package/dist/cjs/cloud/store/FileBrainStore.js.map +1 -1
  75. package/dist/cjs/cloud/store/PostgresBrainStore.d.ts +1 -0
  76. package/dist/cjs/cloud/store/PostgresBrainStore.d.ts.map +1 -1
  77. package/dist/cjs/cloud/store/PostgresBrainStore.js +4 -0
  78. package/dist/cjs/cloud/store/PostgresBrainStore.js.map +1 -1
  79. package/dist/cjs/cloud/v2/app.d.ts.map +1 -1
  80. package/dist/cjs/cloud/v2/app.js +6 -0
  81. package/dist/cjs/cloud/v2/app.js.map +1 -1
  82. package/dist/cjs/cloud/v2/inputGuard.d.ts +23 -0
  83. package/dist/cjs/cloud/v2/inputGuard.d.ts.map +1 -0
  84. package/dist/cjs/cloud/v2/inputGuard.js +71 -0
  85. package/dist/cjs/cloud/v2/inputGuard.js.map +1 -0
  86. package/dist/cjs/cloud/v2/routes/admin.d.ts +24 -0
  87. package/dist/cjs/cloud/v2/routes/admin.d.ts.map +1 -0
  88. package/dist/cjs/cloud/v2/routes/admin.js +329 -0
  89. package/dist/cjs/cloud/v2/routes/admin.js.map +1 -0
  90. package/dist/cjs/cloud/v2/routes/entitlement.d.ts +13 -0
  91. package/dist/cjs/cloud/v2/routes/entitlement.d.ts.map +1 -0
  92. package/dist/cjs/cloud/v2/routes/entitlement.js +24 -0
  93. package/dist/cjs/cloud/v2/routes/entitlement.js.map +1 -0
  94. package/dist/cjs/cloud/v2/routes/index.d.ts +14 -1
  95. package/dist/cjs/cloud/v2/routes/index.d.ts.map +1 -1
  96. package/dist/cjs/cloud/v2/routes/index.js +36 -0
  97. package/dist/cjs/cloud/v2/routes/index.js.map +1 -1
  98. package/dist/cjs/cloud/v2/routes/memories.d.ts +21 -2
  99. package/dist/cjs/cloud/v2/routes/memories.d.ts.map +1 -1
  100. package/dist/cjs/cloud/v2/routes/memories.js +77 -0
  101. package/dist/cjs/cloud/v2/routes/memories.js.map +1 -1
  102. package/dist/cjs/cloud/v2/routes/recall.d.ts +1 -0
  103. package/dist/cjs/cloud/v2/routes/recall.d.ts.map +1 -1
  104. package/dist/cjs/cloud/v2/routes/recall.js +4 -0
  105. package/dist/cjs/cloud/v2/routes/recall.js.map +1 -1
  106. package/dist/cjs/cloud/v2/routes/tenant.d.ts +35 -0
  107. package/dist/cjs/cloud/v2/routes/tenant.d.ts.map +1 -0
  108. package/dist/cjs/cloud/v2/routes/tenant.js +62 -0
  109. package/dist/cjs/cloud/v2/routes/tenant.js.map +1 -0
  110. package/dist/cjs/cloud/v2/routes/usage.d.ts +1 -1
  111. package/dist/cjs/cloud/v2/routes/usage.d.ts.map +1 -1
  112. package/dist/cjs/cloud/v2/routes/verify.d.ts +1 -0
  113. package/dist/cjs/cloud/v2/routes/verify.d.ts.map +1 -1
  114. package/dist/cjs/cloud/v2/routes/verify.js +4 -0
  115. package/dist/cjs/cloud/v2/routes/verify.js.map +1 -1
  116. package/dist/cjs/cloud/v2/server.d.ts +9 -3
  117. package/dist/cjs/cloud/v2/server.d.ts.map +1 -1
  118. package/dist/cjs/cloud/v2/server.js +36 -2
  119. package/dist/cjs/cloud/v2/server.js.map +1 -1
  120. package/dist/cjs/cloud/v2/usageRecorder.d.ts +19 -0
  121. package/dist/cjs/cloud/v2/usageRecorder.d.ts.map +1 -0
  122. package/dist/cjs/cloud/v2/usageRecorder.js +42 -0
  123. package/dist/cjs/cloud/v2/usageRecorder.js.map +1 -0
  124. package/dist/cjs/contracts/api-v2.types.d.ts +90 -2
  125. package/dist/cjs/contracts/api-v2.types.d.ts.map +1 -1
  126. package/dist/cjs/contracts/store.d.ts +2 -0
  127. package/dist/cjs/contracts/store.d.ts.map +1 -1
  128. package/dist/cjs/mcp/index.js +3 -0
  129. package/dist/cjs/mcp/index.js.map +1 -1
  130. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  131. package/dist/cjs/mcp/tools/memory.js +74 -4
  132. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  133. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  134. package/dist/cjs/mcp/tools.js.map +1 -1
  135. package/dist/cjs/proxy/KeyManager.d.ts.map +1 -1
  136. package/dist/cjs/proxy/KeyManager.js +5 -0
  137. package/dist/cjs/proxy/KeyManager.js.map +1 -1
  138. package/dist/cjs/subconscious/CloudBrain.d.ts +77 -0
  139. package/dist/cjs/subconscious/CloudBrain.d.ts.map +1 -0
  140. package/dist/cjs/subconscious/CloudBrain.js +347 -0
  141. package/dist/cjs/subconscious/CloudBrain.js.map +1 -0
  142. package/dist/cjs/subconscious/ProjectIdentity.d.ts +9 -0
  143. package/dist/cjs/subconscious/ProjectIdentity.d.ts.map +1 -0
  144. package/dist/cjs/subconscious/ProjectIdentity.js +63 -0
  145. package/dist/cjs/subconscious/ProjectIdentity.js.map +1 -0
  146. package/dist/cjs/subconscious/TeamBrain.d.ts +9 -3
  147. package/dist/cjs/subconscious/TeamBrain.d.ts.map +1 -1
  148. package/dist/cjs/subconscious/TeamBrain.js +39 -5
  149. package/dist/cjs/subconscious/TeamBrain.js.map +1 -1
  150. package/dist/cjs/utils/ProLicense.d.ts.map +1 -1
  151. package/dist/cjs/utils/ProLicense.js +11 -3
  152. package/dist/cjs/utils/ProLicense.js.map +1 -1
  153. package/dist/cjs/utils/SessionCapture.d.ts +2 -0
  154. package/dist/cjs/utils/SessionCapture.d.ts.map +1 -1
  155. package/dist/cjs/utils/SessionCapture.js +5 -0
  156. package/dist/cjs/utils/SessionCapture.js.map +1 -1
  157. package/dist/cjs/utils/StopNudge.d.ts +8 -0
  158. package/dist/cjs/utils/StopNudge.d.ts.map +1 -0
  159. package/dist/cjs/utils/StopNudge.js +93 -0
  160. package/dist/cjs/utils/StopNudge.js.map +1 -0
  161. package/dist/esm/cli/hostHooks.d.ts +6 -0
  162. package/dist/esm/cli/hostHooks.d.ts.map +1 -1
  163. package/dist/esm/cli/hostHooks.js +12 -2
  164. package/dist/esm/cli/hostHooks.js.map +1 -1
  165. package/dist/esm/cloud/CloudBrainClient.d.ts +52 -0
  166. package/dist/esm/cloud/CloudBrainClient.d.ts.map +1 -0
  167. package/dist/esm/cloud/CloudBrainClient.js +153 -0
  168. package/dist/esm/cloud/CloudBrainClient.js.map +1 -0
  169. package/dist/esm/cloud/CloudConfig.d.ts +41 -0
  170. package/dist/esm/cloud/CloudConfig.d.ts.map +1 -0
  171. package/dist/esm/cloud/CloudConfig.js +118 -0
  172. package/dist/esm/cloud/CloudConfig.js.map +1 -0
  173. package/dist/esm/cloud/CloudEntitlement.d.ts +55 -0
  174. package/dist/esm/cloud/CloudEntitlement.d.ts.map +1 -0
  175. package/dist/esm/cloud/CloudEntitlement.js +159 -0
  176. package/dist/esm/cloud/CloudEntitlement.js.map +1 -0
  177. package/dist/esm/cloud/billing/stripeApi.d.ts +43 -0
  178. package/dist/esm/cloud/billing/stripeApi.d.ts.map +1 -0
  179. package/dist/esm/cloud/billing/stripeApi.js +103 -0
  180. package/dist/esm/cloud/billing/stripeApi.js.map +1 -0
  181. package/dist/esm/cloud/billing/stripeWebhook.d.ts +35 -0
  182. package/dist/esm/cloud/billing/stripeWebhook.d.ts.map +1 -0
  183. package/dist/esm/cloud/billing/stripeWebhook.js +176 -0
  184. package/dist/esm/cloud/billing/stripeWebhook.js.map +1 -0
  185. package/dist/esm/cloud/console/ConsoleStore.d.ts +111 -0
  186. package/dist/esm/cloud/console/ConsoleStore.d.ts.map +1 -0
  187. package/dist/esm/cloud/console/ConsoleStore.js +161 -0
  188. package/dist/esm/cloud/console/ConsoleStore.js.map +1 -0
  189. package/dist/esm/cloud/console/consoleRouter.d.ts +68 -0
  190. package/dist/esm/cloud/console/consoleRouter.d.ts.map +1 -0
  191. package/dist/esm/cloud/console/consoleRouter.js +252 -0
  192. package/dist/esm/cloud/console/consoleRouter.js.map +1 -0
  193. package/dist/esm/cloud/console/mailer.d.ts +22 -0
  194. package/dist/esm/cloud/console/mailer.d.ts.map +1 -0
  195. package/dist/esm/cloud/console/mailer.js +30 -0
  196. package/dist/esm/cloud/console/mailer.js.map +1 -0
  197. package/dist/esm/cloud/identity/PlanPolicy.d.ts +16 -1
  198. package/dist/esm/cloud/identity/PlanPolicy.d.ts.map +1 -1
  199. package/dist/esm/cloud/identity/PlanPolicy.js +46 -6
  200. package/dist/esm/cloud/identity/PlanPolicy.js.map +1 -1
  201. package/dist/esm/cloud/identity/RateLimiter.d.ts +21 -1
  202. package/dist/esm/cloud/identity/RateLimiter.d.ts.map +1 -1
  203. package/dist/esm/cloud/identity/RateLimiter.js +57 -2
  204. package/dist/esm/cloud/identity/RateLimiter.js.map +1 -1
  205. package/dist/esm/cloud/identity/TenantResolver.d.ts +4 -1
  206. package/dist/esm/cloud/identity/TenantResolver.d.ts.map +1 -1
  207. package/dist/esm/cloud/identity/TenantResolver.js +1 -1
  208. package/dist/esm/cloud/identity/TenantResolver.js.map +1 -1
  209. package/dist/esm/cloud/identity/authenticateV2.d.ts.map +1 -1
  210. package/dist/esm/cloud/identity/authenticateV2.js +7 -4
  211. package/dist/esm/cloud/identity/authenticateV2.js.map +1 -1
  212. package/dist/esm/cloud/identity/identityStore.d.ts +85 -10
  213. package/dist/esm/cloud/identity/identityStore.d.ts.map +1 -1
  214. package/dist/esm/cloud/identity/identityStore.js +180 -1
  215. package/dist/esm/cloud/identity/identityStore.js.map +1 -1
  216. package/dist/esm/cloud/metering/PostgresLedgerStore.d.ts +16 -0
  217. package/dist/esm/cloud/metering/PostgresLedgerStore.d.ts.map +1 -0
  218. package/dist/esm/cloud/metering/PostgresLedgerStore.js +40 -0
  219. package/dist/esm/cloud/metering/PostgresLedgerStore.js.map +1 -0
  220. package/dist/esm/cloud/metering/UsageLedger.d.ts +37 -0
  221. package/dist/esm/cloud/metering/UsageLedger.d.ts.map +1 -1
  222. package/dist/esm/cloud/metering/UsageLedger.js +78 -16
  223. package/dist/esm/cloud/metering/UsageLedger.js.map +1 -1
  224. package/dist/esm/cloud/metering/index.d.ts +1 -0
  225. package/dist/esm/cloud/metering/index.d.ts.map +1 -1
  226. package/dist/esm/cloud/metering/index.js +1 -0
  227. package/dist/esm/cloud/metering/index.js.map +1 -1
  228. package/dist/esm/cloud/store/FileBrainStore.d.ts +1 -0
  229. package/dist/esm/cloud/store/FileBrainStore.d.ts.map +1 -1
  230. package/dist/esm/cloud/store/FileBrainStore.js +3 -0
  231. package/dist/esm/cloud/store/FileBrainStore.js.map +1 -1
  232. package/dist/esm/cloud/store/PostgresBrainStore.d.ts +1 -0
  233. package/dist/esm/cloud/store/PostgresBrainStore.d.ts.map +1 -1
  234. package/dist/esm/cloud/store/PostgresBrainStore.js +4 -0
  235. package/dist/esm/cloud/store/PostgresBrainStore.js.map +1 -1
  236. package/dist/esm/cloud/v2/app.d.ts.map +1 -1
  237. package/dist/esm/cloud/v2/app.js +6 -0
  238. package/dist/esm/cloud/v2/app.js.map +1 -1
  239. package/dist/esm/cloud/v2/inputGuard.d.ts +23 -0
  240. package/dist/esm/cloud/v2/inputGuard.d.ts.map +1 -0
  241. package/dist/esm/cloud/v2/inputGuard.js +63 -0
  242. package/dist/esm/cloud/v2/inputGuard.js.map +1 -0
  243. package/dist/esm/cloud/v2/routes/admin.d.ts +24 -0
  244. package/dist/esm/cloud/v2/routes/admin.d.ts.map +1 -0
  245. package/dist/esm/cloud/v2/routes/admin.js +322 -0
  246. package/dist/esm/cloud/v2/routes/admin.js.map +1 -0
  247. package/dist/esm/cloud/v2/routes/entitlement.d.ts +13 -0
  248. package/dist/esm/cloud/v2/routes/entitlement.d.ts.map +1 -0
  249. package/dist/esm/cloud/v2/routes/entitlement.js +21 -0
  250. package/dist/esm/cloud/v2/routes/entitlement.js.map +1 -0
  251. package/dist/esm/cloud/v2/routes/index.d.ts +14 -1
  252. package/dist/esm/cloud/v2/routes/index.d.ts.map +1 -1
  253. package/dist/esm/cloud/v2/routes/index.js +37 -1
  254. package/dist/esm/cloud/v2/routes/index.js.map +1 -1
  255. package/dist/esm/cloud/v2/routes/memories.d.ts +21 -2
  256. package/dist/esm/cloud/v2/routes/memories.d.ts.map +1 -1
  257. package/dist/esm/cloud/v2/routes/memories.js +75 -0
  258. package/dist/esm/cloud/v2/routes/memories.js.map +1 -1
  259. package/dist/esm/cloud/v2/routes/recall.d.ts +1 -0
  260. package/dist/esm/cloud/v2/routes/recall.d.ts.map +1 -1
  261. package/dist/esm/cloud/v2/routes/recall.js +5 -1
  262. package/dist/esm/cloud/v2/routes/recall.js.map +1 -1
  263. package/dist/esm/cloud/v2/routes/tenant.d.ts +35 -0
  264. package/dist/esm/cloud/v2/routes/tenant.d.ts.map +1 -0
  265. package/dist/esm/cloud/v2/routes/tenant.js +58 -0
  266. package/dist/esm/cloud/v2/routes/tenant.js.map +1 -0
  267. package/dist/esm/cloud/v2/routes/usage.d.ts +1 -1
  268. package/dist/esm/cloud/v2/routes/usage.d.ts.map +1 -1
  269. package/dist/esm/cloud/v2/routes/verify.d.ts +1 -0
  270. package/dist/esm/cloud/v2/routes/verify.d.ts.map +1 -1
  271. package/dist/esm/cloud/v2/routes/verify.js +5 -1
  272. package/dist/esm/cloud/v2/routes/verify.js.map +1 -1
  273. package/dist/esm/cloud/v2/server.d.ts +9 -3
  274. package/dist/esm/cloud/v2/server.d.ts.map +1 -1
  275. package/dist/esm/cloud/v2/server.js +36 -3
  276. package/dist/esm/cloud/v2/server.js.map +1 -1
  277. package/dist/esm/cloud/v2/usageRecorder.d.ts +19 -0
  278. package/dist/esm/cloud/v2/usageRecorder.d.ts.map +1 -0
  279. package/dist/esm/cloud/v2/usageRecorder.js +37 -0
  280. package/dist/esm/cloud/v2/usageRecorder.js.map +1 -0
  281. package/dist/esm/contracts/api-v2.types.d.ts +90 -2
  282. package/dist/esm/contracts/api-v2.types.d.ts.map +1 -1
  283. package/dist/esm/contracts/store.d.ts +2 -0
  284. package/dist/esm/contracts/store.d.ts.map +1 -1
  285. package/dist/esm/mcp/index.js +3 -0
  286. package/dist/esm/mcp/index.js.map +1 -1
  287. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  288. package/dist/esm/mcp/tools/memory.js +74 -4
  289. package/dist/esm/mcp/tools/memory.js.map +1 -1
  290. package/dist/esm/mcp/tools.d.ts.map +1 -1
  291. package/dist/esm/mcp/tools.js.map +1 -1
  292. package/dist/esm/proxy/KeyManager.d.ts.map +1 -1
  293. package/dist/esm/proxy/KeyManager.js +5 -0
  294. package/dist/esm/proxy/KeyManager.js.map +1 -1
  295. package/dist/esm/subconscious/CloudBrain.d.ts +77 -0
  296. package/dist/esm/subconscious/CloudBrain.d.ts.map +1 -0
  297. package/dist/esm/subconscious/CloudBrain.js +330 -0
  298. package/dist/esm/subconscious/CloudBrain.js.map +1 -0
  299. package/dist/esm/subconscious/ProjectIdentity.d.ts +9 -0
  300. package/dist/esm/subconscious/ProjectIdentity.d.ts.map +1 -0
  301. package/dist/esm/subconscious/ProjectIdentity.js +56 -0
  302. package/dist/esm/subconscious/ProjectIdentity.js.map +1 -0
  303. package/dist/esm/subconscious/TeamBrain.d.ts +9 -3
  304. package/dist/esm/subconscious/TeamBrain.d.ts.map +1 -1
  305. package/dist/esm/subconscious/TeamBrain.js +39 -7
  306. package/dist/esm/subconscious/TeamBrain.js.map +1 -1
  307. package/dist/esm/utils/ProLicense.d.ts.map +1 -1
  308. package/dist/esm/utils/ProLicense.js +11 -3
  309. package/dist/esm/utils/ProLicense.js.map +1 -1
  310. package/dist/esm/utils/SessionCapture.d.ts +2 -0
  311. package/dist/esm/utils/SessionCapture.d.ts.map +1 -1
  312. package/dist/esm/utils/SessionCapture.js +5 -0
  313. package/dist/esm/utils/SessionCapture.js.map +1 -1
  314. package/dist/esm/utils/StopNudge.d.ts +8 -0
  315. package/dist/esm/utils/StopNudge.d.ts.map +1 -0
  316. package/dist/esm/utils/StopNudge.js +86 -0
  317. package/dist/esm/utils/StopNudge.js.map +1 -0
  318. package/lemma-proxy.cjs +5 -0
  319. package/package.json +2 -1
  320. package/sdks/crewai/dist/ts/src/client.d.ts +5 -1
  321. package/sdks/crewai/dist/ts/src/client.js +8 -0
  322. package/sdks/crewai/dist/ts/src/types.d.ts +32 -1
@@ -0,0 +1,35 @@
1
+ import { type Router } from 'express';
2
+ import type { IdentityStore } from '../identity/identityStore';
3
+ import type { PlanId } from '../identity/PlanPolicy';
4
+ export interface StripeBillingConfig {
5
+ /** `whsec_...` of the webhook endpoint. */
6
+ webhookSecret: string;
7
+ /** Stripe price id -> the Cloud plan it buys. Prices not listed here are not ours. */
8
+ prices: Readonly<Record<string, PlanId>>;
9
+ /** Max age of a signed payload; Stripe's own libraries default to 5 minutes. */
10
+ toleranceSeconds?: number;
11
+ }
12
+ /** Verify `Stripe-Signature` (`t=<unix>,v1=<hex>[,v1=<hex>]`) over `${t}.${rawBody}`. */
13
+ export declare function verifyStripeSignature(rawBody: Buffer, header: string | undefined, secret: string, toleranceSeconds?: number, nowMs?: number): boolean;
14
+ interface StripeEvent {
15
+ id?: string;
16
+ type?: string;
17
+ created?: number;
18
+ data?: {
19
+ object?: Record<string, any>;
20
+ };
21
+ }
22
+ /** `unresolved`: the event is for one of OUR prices but no tenant is linked yet; Stripe must retry it. */
23
+ export type BillingOutcome = 'applied' | 'ignored' | 'stale' | 'unresolved';
24
+ /** Apply one event. Pure of HTTP, so tests drive it without a signature. */
25
+ export declare function applyStripeEvent(event: StripeEvent, store: IdentityStore, config: Pick<StripeBillingConfig, 'prices'>): Promise<BillingOutcome>;
26
+ /** POST /v2/billing/stripe/webhook. Mount BEFORE express.json(): the signature needs the raw bytes. */
27
+ export declare function stripeWebhookRouter(store: IdentityStore, config: StripeBillingConfig): Router;
28
+ /**
29
+ * Reads the Stripe settings from the environment; null when billing is not configured (the route is then not mounted).
30
+ * A plan can be sold through several Stripe prices (monthly, yearly), so each variable takes a comma-separated list:
31
+ * STRIPE_PRICES_VINEL=price_a,price_b
32
+ */
33
+ export declare function stripeConfigFromEnv(env?: NodeJS.ProcessEnv): StripeBillingConfig | null;
34
+ export {};
35
+ //# sourceMappingURL=stripeWebhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripeWebhook.d.ts","sourceRoot":"","sources":["../../../../src/cloud/billing/stripeWebhook.ts"],"names":[],"mappings":"AAiBA,OAAgB,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAA+B,MAAM,2BAA2B,CAAC;AAC5F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,2CAA2C;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACzC,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAKD,yFAAyF;AACzF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,SAAsB,EAAE,KAAK,SAAa,GAAG,OAAO,CAmBtK;AAED,UAAU,WAAW;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,CAAC;CACzC;AAED,0GAA0G;AAC1G,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC;AAgB5E,4EAA4E;AAC5E,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAuDrJ;AAED,uGAAuG;AACvG,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,mBAAmB,GAAG,MAAM,CA4B7F;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,mBAAmB,GAAG,IAAI,CAUpG"}
@@ -0,0 +1,185 @@
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.verifyStripeSignature = verifyStripeSignature;
7
+ exports.applyStripeEvent = applyStripeEvent;
8
+ exports.stripeWebhookRouter = stripeWebhookRouter;
9
+ exports.stripeConfigFromEnv = stripeConfigFromEnv;
10
+ /**
11
+ * Lemma Cloud — Stripe webhook.
12
+ *
13
+ * Stripe owns the money; this turns its subscription events into the tenant's `plan` and the billing
14
+ * state the console shows. Authenticated by the Stripe signature alone (no API key), so it is
15
+ * mounted before the /v2 auth and the JSON parser: the signature covers the RAW body.
16
+ *
17
+ * Shape of the rules, each one a trap if wrong:
18
+ * - The same Stripe account also sells the local Pro license, and every event of the account reaches
19
+ * this endpoint. A subscription whose price is not one of ours, or whose tenant cannot be found,
20
+ * is acknowledged (200) and ignored: a 4xx/5xx would make Stripe retry it for days.
21
+ * - Delivery is unordered, so an event older than the last applied one is dropped (`billing.eventAt`).
22
+ * - A late payment (`past_due`) keeps the plan: the tenant is downgraded when Stripe gives up on the
23
+ * invoice and cancels the subscription (the retry window is set in the Stripe dashboard), not by
24
+ * a timer here. `unpaid`, `canceled` and `incomplete_expired` drop the tenant to `free`.
25
+ */
26
+ const crypto_1 = __importDefault(require("crypto"));
27
+ const express_1 = __importDefault(require("express"));
28
+ const DEFAULT_TOLERANCE_S = 300;
29
+ const MAX_BODY_BYTES = 256 * 1024;
30
+ /** Verify `Stripe-Signature` (`t=<unix>,v1=<hex>[,v1=<hex>]`) over `${t}.${rawBody}`. */
31
+ function verifyStripeSignature(rawBody, header, secret, toleranceSeconds = DEFAULT_TOLERANCE_S, nowMs = Date.now()) {
32
+ if (!header)
33
+ return false;
34
+ let t = '';
35
+ const sigs = [];
36
+ for (const part of header.split(',')) {
37
+ const i = part.indexOf('=');
38
+ if (i < 0)
39
+ continue;
40
+ const k = part.slice(0, i).trim();
41
+ const v = part.slice(i + 1).trim();
42
+ if (k === 't')
43
+ t = v;
44
+ else if (k === 'v1')
45
+ sigs.push(v);
46
+ }
47
+ if (!/^\d{1,12}$/.test(t) || sigs.length === 0)
48
+ return false;
49
+ if (Math.abs(nowMs / 1000 - Number(t)) > toleranceSeconds)
50
+ return false;
51
+ const expected = crypto_1.default.createHmac('sha256', secret).update(`${t}.`).update(rawBody).digest();
52
+ return sigs.some((s) => {
53
+ if (!/^[0-9a-f]{64}$/i.test(s))
54
+ return false;
55
+ return crypto_1.default.timingSafeEqual(expected, Buffer.from(s, 'hex'));
56
+ });
57
+ }
58
+ const asId = (v) => {
59
+ if (typeof v === 'string' && v)
60
+ return v;
61
+ if (v && typeof v === 'object' && typeof v.id === 'string')
62
+ return v.id;
63
+ return null;
64
+ };
65
+ /** Stripe moved `current_period_end` from the subscription to its items in newer API versions; accept both. */
66
+ const periodEndMs = (sub) => {
67
+ const s = sub.current_period_end ?? sub.items?.data?.[0]?.current_period_end;
68
+ return typeof s === 'number' ? s * 1000 : null;
69
+ };
70
+ const DROPS_TO_FREE = new Set(['unpaid', 'canceled', 'incomplete_expired']);
71
+ /** Apply one event. Pure of HTTP, so tests drive it without a signature. */
72
+ async function applyStripeEvent(event, store, config) {
73
+ const obj = event.data?.object;
74
+ if (!obj || typeof event.created !== 'number')
75
+ return 'ignored';
76
+ const eventAt = event.created * 1000;
77
+ let tenant = null;
78
+ let next = null;
79
+ if (event.type === 'checkout.session.completed') {
80
+ // Links the Stripe customer to our tenant (client_reference_id is the tenant id the checkout was created for).
81
+ const tenantId = typeof obj.client_reference_id === 'string' ? obj.client_reference_id : null;
82
+ const customerId = asId(obj.customer);
83
+ if (!tenantId || !customerId || obj.mode !== 'subscription')
84
+ return 'ignored';
85
+ tenant = await store.getTenant(tenantId);
86
+ if (!tenant || tenant.plan === 'internal')
87
+ return 'ignored';
88
+ // One Stripe customer belongs to one tenant. A checkout naming a customer that is already
89
+ // linked elsewhere is refused, not re-pointed (the unique index would turn it into a 500).
90
+ const owner = await store.findTenantByStripeCustomer(customerId);
91
+ if (owner && owner.id !== tenant.id)
92
+ return 'ignored';
93
+ next = { plan: tenant.plan, billing: { ...tenant.billing, customerId, subscriptionId: asId(obj.subscription) ?? tenant.billing.subscriptionId, eventAt } };
94
+ }
95
+ else if (event.type === 'customer.subscription.created' || event.type === 'customer.subscription.updated' || event.type === 'customer.subscription.deleted') {
96
+ const priceId = asId(obj.items?.data?.[0]?.price);
97
+ const bought = priceId ? config.prices[priceId] : undefined;
98
+ if (!bought)
99
+ return 'ignored'; // not a Cloud price: the local Pro license, or something else of the account
100
+ const customerId = asId(obj.customer);
101
+ const metaTenant = typeof obj.metadata?.tenantId === 'string' ? obj.metadata.tenantId : null;
102
+ tenant = metaTenant ? await store.getTenant(metaTenant) : customerId ? await store.findTenantByStripeCustomer(customerId) : null;
103
+ // A price of ours with no tenant yet usually means this event overtook `checkout.session.completed`
104
+ // (Stripe does not order them): answering 200 would lose the plan for good, so ask for a retry.
105
+ if (!tenant)
106
+ return 'unresolved';
107
+ if (tenant.plan === 'internal')
108
+ return 'ignored'; // not sold through Stripe: nothing it says may change it
109
+ const status = typeof obj.status === 'string' ? obj.status : null;
110
+ const gone = event.type === 'customer.subscription.deleted' || (status !== null && DROPS_TO_FREE.has(status));
111
+ // `incomplete` (first payment pending) changes nothing yet; the next event carries the outcome.
112
+ if (!gone && status === 'incomplete')
113
+ return 'ignored';
114
+ next = {
115
+ plan: gone ? 'free' : bought,
116
+ billing: {
117
+ customerId: customerId ?? tenant.billing.customerId,
118
+ subscriptionId: asId(obj.id) ?? tenant.billing.subscriptionId,
119
+ status: event.type === 'customer.subscription.deleted' ? 'canceled' : status,
120
+ currentPeriodEnd: periodEndMs(obj) ?? tenant.billing.currentPeriodEnd,
121
+ pastDueSince: status === 'past_due' ? tenant.billing.pastDueSince ?? eventAt : null,
122
+ eventAt,
123
+ },
124
+ };
125
+ }
126
+ else {
127
+ return 'ignored';
128
+ }
129
+ const result = await store.applyBilling(tenant.id, next.plan, next.billing);
130
+ if (result.ok)
131
+ return 'applied';
132
+ return result.reason === 'stale' ? 'stale' : 'ignored';
133
+ }
134
+ /** POST /v2/billing/stripe/webhook. Mount BEFORE express.json(): the signature needs the raw bytes. */
135
+ function stripeWebhookRouter(store, config) {
136
+ const r = express_1.default.Router();
137
+ r.post('/', express_1.default.raw({ type: '*/*', limit: MAX_BODY_BYTES }), async (req, res, next) => {
138
+ try {
139
+ const raw = req.body;
140
+ if (!Buffer.isBuffer(raw) || !verifyStripeSignature(raw, req.header('stripe-signature'), config.webhookSecret, config.toleranceSeconds)) {
141
+ res.status(400).json({ error: { code: 'invalid_signature', status: 400, message: 'bad or missing Stripe signature' } });
142
+ return;
143
+ }
144
+ let event;
145
+ try {
146
+ event = JSON.parse(raw.toString('utf8'));
147
+ }
148
+ catch {
149
+ res.status(400).json({ error: { code: 'invalid_request', status: 400, message: 'body is not JSON' } });
150
+ return;
151
+ }
152
+ const outcome = await applyStripeEvent(event, store, config);
153
+ if (outcome === 'unresolved') {
154
+ // 409, not 2xx: Stripe retries with backoff for days, by which time the checkout event has linked the tenant.
155
+ res.status(409).json({ error: { code: 'tenant_not_linked', status: 409, message: 'no tenant linked to this customer yet, retry later' }, outcome });
156
+ return;
157
+ }
158
+ res.json({ received: true, outcome });
159
+ }
160
+ catch (err) {
161
+ next(err); // a store failure is a 500: Stripe retries, which is what we want
162
+ }
163
+ });
164
+ return r;
165
+ }
166
+ /**
167
+ * Reads the Stripe settings from the environment; null when billing is not configured (the route is then not mounted).
168
+ * A plan can be sold through several Stripe prices (monthly, yearly), so each variable takes a comma-separated list:
169
+ * STRIPE_PRICES_VINEL=price_a,price_b
170
+ */
171
+ function stripeConfigFromEnv(env = process.env) {
172
+ const webhookSecret = env.STRIPE_WEBHOOK_SECRET;
173
+ if (!webhookSecret)
174
+ return null;
175
+ const prices = {};
176
+ const add = (list, plan) => {
177
+ for (const id of (list ?? '').split(','))
178
+ if (id.trim())
179
+ prices[id.trim()] = plan;
180
+ };
181
+ add(env.STRIPE_PRICES_VINEL, 'vinel');
182
+ add(env.STRIPE_PRICES_REGNUM, 'regnum');
183
+ return { webhookSecret, prices };
184
+ }
185
+ //# sourceMappingURL=stripeWebhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripeWebhook.js","sourceRoot":"","sources":["../../../../src/cloud/billing/stripeWebhook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ import type { Pool } from 'pg';
2
+ import type { IdentityStore } from '../identity/identityStore';
3
+ export declare const MEMBER_ROLES: readonly ["owner", "admin", "member"];
4
+ export type MemberRole = (typeof MEMBER_ROLES)[number];
5
+ export interface Member {
6
+ id: string;
7
+ tenantId: string;
8
+ email: string;
9
+ role: MemberRole;
10
+ createdAt: number;
11
+ }
12
+ export type AddMemberResult = {
13
+ ok: true;
14
+ member: Member;
15
+ } | {
16
+ ok: false;
17
+ reason: 'no_tenant' | 'exists' | 'other_tenant';
18
+ };
19
+ export interface SessionInfo {
20
+ tenantId: string;
21
+ email: string;
22
+ role: MemberRole;
23
+ }
24
+ export interface ConsoleStore {
25
+ addMember(tenantId: string, email: string, role: MemberRole): Promise<AddMemberResult>;
26
+ listMembers(tenantId: string): Promise<Member[]>;
27
+ /** Soft-removes the member and ends their sessions. */
28
+ removeMember(tenantId: string, email: string): Promise<boolean>;
29
+ /** The active member with this email, in any tenant. */
30
+ findMemberByEmail(email: string): Promise<Member | null>;
31
+ createLoginToken(input: {
32
+ tokenHash: string;
33
+ tenantId: string;
34
+ email: string;
35
+ expiresAt: number;
36
+ }): Promise<void>;
37
+ /** Atomic and single use: the first caller gets the member, everyone after (or after expiry) gets null. */
38
+ consumeLoginToken(tokenHash: string, now: number): Promise<{
39
+ tenantId: string;
40
+ email: string;
41
+ } | null>;
42
+ createSession(input: {
43
+ tokenHash: string;
44
+ tenantId: string;
45
+ email: string;
46
+ expiresAt: number;
47
+ }): Promise<void>;
48
+ /** The session if it is live AND its member is still active; the role is the member's current one. */
49
+ findSession(tokenHash: string, now: number): Promise<SessionInfo | null>;
50
+ deleteSession(tokenHash: string): Promise<void>;
51
+ }
52
+ export declare const normalizeEmail: (email: string) => string;
53
+ export declare const hashToken: (token: string) => string;
54
+ /** 256 bits, URL-safe. Only its hash is ever stored. */
55
+ export declare const newToken: () => string;
56
+ export declare class InMemoryConsoleStore implements ConsoleStore {
57
+ private readonly identity;
58
+ private readonly members;
59
+ private readonly loginTokens;
60
+ private readonly sessions;
61
+ constructor(identity: Pick<IdentityStore, 'getTenant'>);
62
+ addMember(tenantId: string, rawEmail: string, role: MemberRole): Promise<AddMemberResult>;
63
+ listMembers(tenantId: string): Promise<Member[]>;
64
+ removeMember(tenantId: string, rawEmail: string): Promise<boolean>;
65
+ findMemberByEmail(rawEmail: string): Promise<Member | null>;
66
+ createLoginToken(i: {
67
+ tokenHash: string;
68
+ tenantId: string;
69
+ email: string;
70
+ expiresAt: number;
71
+ }): Promise<void>;
72
+ consumeLoginToken(tokenHash: string, now: number): Promise<{
73
+ tenantId: string;
74
+ email: string;
75
+ } | null>;
76
+ createSession(i: {
77
+ tokenHash: string;
78
+ tenantId: string;
79
+ email: string;
80
+ expiresAt: number;
81
+ }): Promise<void>;
82
+ findSession(tokenHash: string, now: number): Promise<SessionInfo | null>;
83
+ deleteSession(tokenHash: string): Promise<void>;
84
+ }
85
+ export declare class PostgresConsoleStore implements ConsoleStore {
86
+ private readonly pool;
87
+ constructor(pool: Pool);
88
+ addMember(tenantId: string, rawEmail: string, role: MemberRole): Promise<AddMemberResult>;
89
+ listMembers(tenantId: string): Promise<Member[]>;
90
+ removeMember(tenantId: string, rawEmail: string): Promise<boolean>;
91
+ findMemberByEmail(rawEmail: string): Promise<Member | null>;
92
+ createLoginToken(i: {
93
+ tokenHash: string;
94
+ tenantId: string;
95
+ email: string;
96
+ expiresAt: number;
97
+ }): Promise<void>;
98
+ consumeLoginToken(tokenHash: string, now: number): Promise<{
99
+ tenantId: string;
100
+ email: string;
101
+ } | null>;
102
+ createSession(i: {
103
+ tokenHash: string;
104
+ tenantId: string;
105
+ email: string;
106
+ expiresAt: number;
107
+ }): Promise<void>;
108
+ findSession(tokenHash: string, now: number): Promise<SessionInfo | null>;
109
+ deleteSession(tokenHash: string): Promise<void>;
110
+ }
111
+ //# sourceMappingURL=ConsoleStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsoleStore.d.ts","sourceRoot":"","sources":["../../../../src/cloud/console/ConsoleStore.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,eAAO,MAAM,YAAY,uCAAwC,CAAC;AAClE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,cAAc,CAAA;CAAE,CAAC;AAEnE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACvF,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjD,uDAAuD;IACvD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChE,wDAAwD;IACxD,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAEzD,gBAAgB,CAAC,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClH,2GAA2G;IAC3G,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAEvG,aAAa,CAAC,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/G,sGAAsG;IACtG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzE,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAED,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,MAAoC,CAAC;AACpF,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,KAAG,MAAiE,CAAC;AAC5G,wDAAwD;AACxD,eAAO,MAAM,QAAQ,QAAO,MAAsD,CAAC;AAOnF,qBAAa,oBAAqB,YAAW,YAAY;IAK3C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4F;IACxH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6E;gBAEzE,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC;IAEjE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC;IAUzF,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAIhD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASlE,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAM3D,gBAAgB,CAAC,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7G,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAOtG,aAAa,CAAC,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1G,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAOxE,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGtD;AAID,qBAAa,oBAAqB,YAAW,YAAY;IAC3C,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAEjC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC;IAyBzF,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAQhD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOlE,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQ3D,gBAAgB,CAAC,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7G,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAatG,aAAa,CAAC,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1G,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAWxE,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGtD"}
@@ -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":"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"}
@@ -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'>;
39
+ usageLedger?: Pick<UsageLedger, 'computeUsage' | 'computeKeyActivity'>;
40
+ stripeApi?: Pick<StripeApi, 'createPortal'>;
41
+ mailer?: LoginMailer;
42
+ /** Where the app is reachable, for links in emails. Falls back to the request's own host. */
43
+ publicBaseUrl?: string;
44
+ /** Directory holding index.html, app.js, styles.css. */
45
+ consoleDir?: string;
46
+ /** Drop the Secure flag on the cookie: plain-http local development only. */
47
+ insecureCookies?: boolean;
48
+ now?: () => number;
49
+ }
50
+ /** Counts attempts per key inside a sliding window. Per instance: enough to blunt abuse, not a security boundary. */
51
+ export declare class AttemptLimiter {
52
+ private readonly max;
53
+ private readonly windowMs;
54
+ private readonly hits;
55
+ constructor(max: number, windowMs: number);
56
+ allow(key: string, now: number): boolean;
57
+ }
58
+ /** The origin the app is served from: configured, else what the proxy in front of us says. */
59
+ export declare function publicBase(req: Request, configured?: string): string;
60
+ export declare const loginLink: (base: string, token: string) => string;
61
+ /** Issues a one-time link for an ACTIVE member; null when the email is not one. Shared with the operator route. */
62
+ export declare function issueLoginLink(store: ConsoleStore, email: string, now: number): Promise<{
63
+ token: string;
64
+ email: string;
65
+ expiresAt: number;
66
+ } | null>;
67
+ export declare function consoleRouter(deps: ConsoleDeps): Router;
68
+ //# sourceMappingURL=consoleRouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consoleRouter.d.ts","sourceRoot":"","sources":["../../../../src/cloud/console/consoleRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAgB,EAAqB,KAAK,OAAO,EAAsC,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAKpH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAuC,KAAK,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAC1G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,YAAY,IAAI,CAAC;AAI9B,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,KAAK,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAClC,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,GAAG,oBAAoB,CAAC,CAAC;IACvE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAC5C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qHAAqH;AACrH,qBAAa,cAAc;IAGvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAH3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;gBAEjC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM;IAEnC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;CAWzC;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,MAA2C,CAAC;AAEpG,mHAAmH;AACnH,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAOrE;AAkBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CA+MvD"}