palaryn 0.1.0 → 0.3.2

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 (344) hide show
  1. package/README.md +243 -588
  2. package/dist/sdk/typescript/src/client.js +2 -2
  3. package/dist/sdk/typescript/src/client.js.map +1 -1
  4. package/dist/src/anomaly/detector.d.ts +7 -4
  5. package/dist/src/anomaly/detector.d.ts.map +1 -1
  6. package/dist/src/anomaly/detector.js +22 -12
  7. package/dist/src/anomaly/detector.js.map +1 -1
  8. package/dist/src/audit/logger.d.ts +10 -0
  9. package/dist/src/audit/logger.d.ts.map +1 -1
  10. package/dist/src/audit/logger.js +52 -38
  11. package/dist/src/audit/logger.js.map +1 -1
  12. package/dist/src/auth/routes.d.ts.map +1 -1
  13. package/dist/src/auth/routes.js +35 -0
  14. package/dist/src/auth/routes.js.map +1 -1
  15. package/dist/src/budget/manager.d.ts +5 -0
  16. package/dist/src/budget/manager.d.ts.map +1 -1
  17. package/dist/src/budget/manager.js +32 -0
  18. package/dist/src/budget/manager.js.map +1 -1
  19. package/dist/src/budget/model-pricing.d.ts +20 -0
  20. package/dist/src/budget/model-pricing.d.ts.map +1 -0
  21. package/dist/src/budget/model-pricing.js +107 -0
  22. package/dist/src/budget/model-pricing.js.map +1 -0
  23. package/dist/src/budget/usage-extractor.d.ts +3 -1
  24. package/dist/src/budget/usage-extractor.d.ts.map +1 -1
  25. package/dist/src/budget/usage-extractor.js +47 -3
  26. package/dist/src/budget/usage-extractor.js.map +1 -1
  27. package/dist/src/config/defaults.d.ts.map +1 -1
  28. package/dist/src/config/defaults.js +65 -13
  29. package/dist/src/config/defaults.js.map +1 -1
  30. package/dist/src/dlp/tool-patterns.d.ts +7 -0
  31. package/dist/src/dlp/tool-patterns.d.ts.map +1 -0
  32. package/dist/src/dlp/tool-patterns.js +34 -0
  33. package/dist/src/dlp/tool-patterns.js.map +1 -0
  34. package/dist/src/executor/filesystem-executor.d.ts +28 -0
  35. package/dist/src/executor/filesystem-executor.d.ts.map +1 -0
  36. package/dist/src/executor/filesystem-executor.js +192 -0
  37. package/dist/src/executor/filesystem-executor.js.map +1 -0
  38. package/dist/src/executor/http-executor.d.ts.map +1 -1
  39. package/dist/src/executor/http-executor.js +22 -2
  40. package/dist/src/executor/http-executor.js.map +1 -1
  41. package/dist/src/executor/index.d.ts +4 -0
  42. package/dist/src/executor/index.d.ts.map +1 -1
  43. package/dist/src/executor/index.js +9 -1
  44. package/dist/src/executor/index.js.map +1 -1
  45. package/dist/src/executor/shell-executor.d.ts +22 -0
  46. package/dist/src/executor/shell-executor.d.ts.map +1 -0
  47. package/dist/src/executor/shell-executor.js +119 -0
  48. package/dist/src/executor/shell-executor.js.map +1 -0
  49. package/dist/src/executor/sql-executor.d.ts +29 -0
  50. package/dist/src/executor/sql-executor.d.ts.map +1 -0
  51. package/dist/src/executor/sql-executor.js +114 -0
  52. package/dist/src/executor/sql-executor.js.map +1 -0
  53. package/dist/src/executor/websocket-executor.d.ts +26 -0
  54. package/dist/src/executor/websocket-executor.d.ts.map +1 -0
  55. package/dist/src/executor/websocket-executor.js +205 -0
  56. package/dist/src/executor/websocket-executor.js.map +1 -0
  57. package/dist/src/interceptor/index.d.ts +2 -0
  58. package/dist/src/interceptor/index.d.ts.map +1 -0
  59. package/dist/src/interceptor/index.js +6 -0
  60. package/dist/src/interceptor/index.js.map +1 -0
  61. package/dist/src/interceptor/provider-interceptor.d.ts +36 -0
  62. package/dist/src/interceptor/provider-interceptor.d.ts.map +1 -0
  63. package/dist/src/interceptor/provider-interceptor.js +302 -0
  64. package/dist/src/interceptor/provider-interceptor.js.map +1 -0
  65. package/dist/src/mcp/auth-verifier.d.ts.map +1 -1
  66. package/dist/src/mcp/auth-verifier.js +3 -2
  67. package/dist/src/mcp/auth-verifier.js.map +1 -1
  68. package/dist/src/mcp/bridge.d.ts +14 -10
  69. package/dist/src/mcp/bridge.d.ts.map +1 -1
  70. package/dist/src/mcp/bridge.js +51 -227
  71. package/dist/src/mcp/bridge.js.map +1 -1
  72. package/dist/src/mcp/http-transport.d.ts +2 -0
  73. package/dist/src/mcp/http-transport.d.ts.map +1 -1
  74. package/dist/src/mcp/http-transport.js +117 -66
  75. package/dist/src/mcp/http-transport.js.map +1 -1
  76. package/dist/src/mcp/internal-auth.d.ts +13 -0
  77. package/dist/src/mcp/internal-auth.d.ts.map +1 -0
  78. package/dist/src/mcp/internal-auth.js +12 -0
  79. package/dist/src/mcp/internal-auth.js.map +1 -0
  80. package/dist/src/mcp/tool-definitions.d.ts +41 -0
  81. package/dist/src/mcp/tool-definitions.d.ts.map +1 -0
  82. package/dist/src/mcp/tool-definitions.js +491 -0
  83. package/dist/src/mcp/tool-definitions.js.map +1 -0
  84. package/dist/src/middleware/auth.js.map +1 -1
  85. package/dist/src/middleware/session.js.map +1 -1
  86. package/dist/src/middleware/validate.d.ts +8 -0
  87. package/dist/src/middleware/validate.d.ts.map +1 -1
  88. package/dist/src/middleware/validate.js +45 -0
  89. package/dist/src/middleware/validate.js.map +1 -1
  90. package/dist/src/policy/engine.d.ts +4 -0
  91. package/dist/src/policy/engine.d.ts.map +1 -1
  92. package/dist/src/policy/engine.js +117 -0
  93. package/dist/src/policy/engine.js.map +1 -1
  94. package/dist/src/saas/routes.d.ts.map +1 -1
  95. package/dist/src/saas/routes.js +355 -22
  96. package/dist/src/saas/routes.js.map +1 -1
  97. package/dist/src/server/app.d.ts.map +1 -1
  98. package/dist/src/server/app.js +24 -3
  99. package/dist/src/server/app.js.map +1 -1
  100. package/dist/src/server/gateway.d.ts.map +1 -1
  101. package/dist/src/server/gateway.js +17 -0
  102. package/dist/src/server/gateway.js.map +1 -1
  103. package/dist/src/server/index.d.ts.map +1 -1
  104. package/dist/src/server/index.js +18 -0
  105. package/dist/src/server/index.js.map +1 -1
  106. package/dist/src/storage/interfaces.d.ts +14 -3
  107. package/dist/src/storage/interfaces.d.ts.map +1 -1
  108. package/dist/src/storage/memory.d.ts +2 -0
  109. package/dist/src/storage/memory.d.ts.map +1 -1
  110. package/dist/src/storage/memory.js +6 -0
  111. package/dist/src/storage/memory.js.map +1 -1
  112. package/dist/src/storage/postgres.d.ts +5 -0
  113. package/dist/src/storage/postgres.d.ts.map +1 -1
  114. package/dist/src/storage/postgres.js +16 -0
  115. package/dist/src/storage/postgres.js.map +1 -1
  116. package/dist/src/storage/redis.d.ts +10 -0
  117. package/dist/src/storage/redis.d.ts.map +1 -1
  118. package/dist/src/storage/redis.js +65 -0
  119. package/dist/src/storage/redis.js.map +1 -1
  120. package/dist/src/types/budget.d.ts +4 -0
  121. package/dist/src/types/budget.d.ts.map +1 -1
  122. package/dist/src/types/config.d.ts +58 -0
  123. package/dist/src/types/config.d.ts.map +1 -1
  124. package/dist/src/types/events.d.ts +1 -0
  125. package/dist/src/types/events.d.ts.map +1 -1
  126. package/dist/src/types/policy.d.ts +11 -1
  127. package/dist/src/types/policy.d.ts.map +1 -1
  128. package/dist/src/types/tool-result.d.ts +11 -0
  129. package/dist/src/types/tool-result.d.ts.map +1 -1
  130. package/dist/tests/unit/app-routes.test.d.ts +2 -0
  131. package/dist/tests/unit/app-routes.test.d.ts.map +1 -0
  132. package/dist/tests/unit/app-routes.test.js +715 -0
  133. package/dist/tests/unit/app-routes.test.js.map +1 -0
  134. package/dist/tests/unit/audit-logger.test.js +105 -0
  135. package/dist/tests/unit/audit-logger.test.js.map +1 -1
  136. package/dist/tests/unit/auth-providers.test.d.ts +2 -0
  137. package/dist/tests/unit/auth-providers.test.d.ts.map +1 -0
  138. package/dist/tests/unit/auth-providers.test.js +279 -0
  139. package/dist/tests/unit/auth-providers.test.js.map +1 -0
  140. package/dist/tests/unit/auth-routes-extended.test.d.ts +2 -0
  141. package/dist/tests/unit/auth-routes-extended.test.d.ts.map +1 -0
  142. package/dist/tests/unit/auth-routes-extended.test.js +993 -0
  143. package/dist/tests/unit/auth-routes-extended.test.js.map +1 -0
  144. package/dist/tests/unit/auth-verifier.test.d.ts +2 -0
  145. package/dist/tests/unit/auth-verifier.test.d.ts.map +1 -0
  146. package/dist/tests/unit/auth-verifier.test.js +505 -0
  147. package/dist/tests/unit/auth-verifier.test.js.map +1 -0
  148. package/dist/tests/unit/billing-routes.test.d.ts +2 -0
  149. package/dist/tests/unit/billing-routes.test.d.ts.map +1 -0
  150. package/dist/tests/unit/billing-routes.test.js +432 -0
  151. package/dist/tests/unit/billing-routes.test.js.map +1 -0
  152. package/dist/tests/unit/config-defaults.test.d.ts +2 -0
  153. package/dist/tests/unit/config-defaults.test.d.ts.map +1 -0
  154. package/dist/tests/unit/config-defaults.test.js +119 -0
  155. package/dist/tests/unit/config-defaults.test.js.map +1 -0
  156. package/dist/tests/unit/defaults.test.js +0 -10
  157. package/dist/tests/unit/defaults.test.js.map +1 -1
  158. package/dist/tests/unit/filesystem-executor.test.d.ts +2 -0
  159. package/dist/tests/unit/filesystem-executor.test.d.ts.map +1 -0
  160. package/dist/tests/unit/filesystem-executor.test.js +280 -0
  161. package/dist/tests/unit/filesystem-executor.test.js.map +1 -0
  162. package/dist/tests/unit/gateway-branches.test.d.ts +2 -0
  163. package/dist/tests/unit/gateway-branches.test.d.ts.map +1 -0
  164. package/dist/tests/unit/gateway-branches.test.js +1039 -0
  165. package/dist/tests/unit/gateway-branches.test.js.map +1 -0
  166. package/dist/tests/unit/http-executor-branches.test.d.ts +2 -0
  167. package/dist/tests/unit/http-executor-branches.test.d.ts.map +1 -0
  168. package/dist/tests/unit/http-executor-branches.test.js +495 -0
  169. package/dist/tests/unit/http-executor-branches.test.js.map +1 -0
  170. package/dist/tests/unit/logger.test.d.ts +2 -0
  171. package/dist/tests/unit/logger.test.d.ts.map +1 -0
  172. package/dist/tests/unit/logger.test.js +97 -0
  173. package/dist/tests/unit/logger.test.js.map +1 -0
  174. package/dist/tests/unit/mcp-internal-auth.test.d.ts +2 -0
  175. package/dist/tests/unit/mcp-internal-auth.test.d.ts.map +1 -0
  176. package/dist/tests/unit/mcp-internal-auth.test.js +445 -0
  177. package/dist/tests/unit/mcp-internal-auth.test.js.map +1 -0
  178. package/dist/tests/unit/metrics.test.js +102 -0
  179. package/dist/tests/unit/metrics.test.js.map +1 -1
  180. package/dist/tests/unit/model-pricing.test.d.ts +2 -0
  181. package/dist/tests/unit/model-pricing.test.d.ts.map +1 -0
  182. package/dist/tests/unit/model-pricing.test.js +87 -0
  183. package/dist/tests/unit/model-pricing.test.js.map +1 -0
  184. package/dist/tests/unit/oauth-stores.test.d.ts +2 -0
  185. package/dist/tests/unit/oauth-stores.test.d.ts.map +1 -0
  186. package/dist/tests/unit/oauth-stores.test.js +260 -0
  187. package/dist/tests/unit/oauth-stores.test.js.map +1 -0
  188. package/dist/tests/unit/policy-engine.test.js +466 -0
  189. package/dist/tests/unit/policy-engine.test.js.map +1 -1
  190. package/dist/tests/unit/provider-interceptor.test.d.ts +2 -0
  191. package/dist/tests/unit/provider-interceptor.test.d.ts.map +1 -0
  192. package/dist/tests/unit/provider-interceptor.test.js +472 -0
  193. package/dist/tests/unit/provider-interceptor.test.js.map +1 -0
  194. package/dist/tests/unit/saas-routes-branches.test.d.ts +2 -0
  195. package/dist/tests/unit/saas-routes-branches.test.d.ts.map +1 -0
  196. package/dist/tests/unit/saas-routes-branches.test.js +2165 -0
  197. package/dist/tests/unit/saas-routes-branches.test.js.map +1 -0
  198. package/dist/tests/unit/saas-routes-crud.test.d.ts +2 -0
  199. package/dist/tests/unit/saas-routes-crud.test.d.ts.map +1 -0
  200. package/dist/tests/unit/saas-routes-crud.test.js +332 -0
  201. package/dist/tests/unit/saas-routes-crud.test.js.map +1 -0
  202. package/dist/tests/unit/saas-routes-data.test.d.ts +2 -0
  203. package/dist/tests/unit/saas-routes-data.test.d.ts.map +1 -0
  204. package/dist/tests/unit/saas-routes-data.test.js +405 -0
  205. package/dist/tests/unit/saas-routes-data.test.js.map +1 -0
  206. package/dist/tests/unit/saas-routes.test.js +3 -3
  207. package/dist/tests/unit/saas-routes.test.js.map +1 -1
  208. package/dist/tests/unit/shell-executor.test.d.ts +2 -0
  209. package/dist/tests/unit/shell-executor.test.d.ts.map +1 -0
  210. package/dist/tests/unit/shell-executor.test.js +145 -0
  211. package/dist/tests/unit/shell-executor.test.js.map +1 -0
  212. package/dist/tests/unit/sql-executor.test.d.ts +2 -0
  213. package/dist/tests/unit/sql-executor.test.d.ts.map +1 -0
  214. package/dist/tests/unit/sql-executor.test.js +177 -0
  215. package/dist/tests/unit/sql-executor.test.js.map +1 -0
  216. package/dist/tests/unit/stream-proxy.test.d.ts +2 -0
  217. package/dist/tests/unit/stream-proxy.test.d.ts.map +1 -0
  218. package/dist/tests/unit/stream-proxy.test.js +147 -0
  219. package/dist/tests/unit/stream-proxy.test.js.map +1 -0
  220. package/dist/tests/unit/tool-definitions.test.d.ts +2 -0
  221. package/dist/tests/unit/tool-definitions.test.d.ts.map +1 -0
  222. package/dist/tests/unit/tool-definitions.test.js +184 -0
  223. package/dist/tests/unit/tool-definitions.test.js.map +1 -0
  224. package/dist/tests/unit/usage-extractor.test.js +140 -0
  225. package/dist/tests/unit/usage-extractor.test.js.map +1 -1
  226. package/dist/tests/unit/webhook-handler.test.d.ts +2 -0
  227. package/dist/tests/unit/webhook-handler.test.d.ts.map +1 -0
  228. package/dist/tests/unit/webhook-handler.test.js +453 -0
  229. package/dist/tests/unit/webhook-handler.test.js.map +1 -0
  230. package/dist/tests/unit/webhook-routes.test.d.ts +2 -0
  231. package/dist/tests/unit/webhook-routes.test.d.ts.map +1 -0
  232. package/dist/tests/unit/webhook-routes.test.js +69 -0
  233. package/dist/tests/unit/webhook-routes.test.js.map +1 -0
  234. package/dist/tests/unit/websocket-executor.test.d.ts +2 -0
  235. package/dist/tests/unit/websocket-executor.test.d.ts.map +1 -0
  236. package/dist/tests/unit/websocket-executor.test.js +121 -0
  237. package/dist/tests/unit/websocket-executor.test.js.map +1 -0
  238. package/package.json +8 -2
  239. package/policy-packs/demo_fail.yaml +41 -0
  240. package/policy-packs/full_tools.yaml +136 -0
  241. package/src/admin/index.ts +1 -0
  242. package/src/admin/routes.ts +509 -0
  243. package/src/admin/templates.ts +572 -0
  244. package/src/anomaly/detector.ts +730 -0
  245. package/src/anomaly/index.ts +1 -0
  246. package/src/approval/manager.ts +569 -0
  247. package/src/approval/webhook.ts +133 -0
  248. package/src/audit/logger.ts +490 -0
  249. package/src/auth/index.ts +5 -0
  250. package/src/auth/password.ts +21 -0
  251. package/src/auth/pkce.ts +22 -0
  252. package/src/auth/providers.ts +208 -0
  253. package/src/auth/routes.ts +561 -0
  254. package/src/auth/session.ts +84 -0
  255. package/src/billing/index.ts +6 -0
  256. package/src/billing/plan-enforcer.ts +135 -0
  257. package/src/billing/routes.ts +229 -0
  258. package/src/billing/stripe-client.ts +58 -0
  259. package/src/billing/webhook-handler.ts +182 -0
  260. package/src/billing/webhook-routes.ts +28 -0
  261. package/src/budget/manager.ts +679 -0
  262. package/src/budget/model-pricing.ts +119 -0
  263. package/src/budget/usage-extractor.ts +214 -0
  264. package/src/cli.ts +91 -0
  265. package/src/config/defaults.ts +261 -0
  266. package/src/config/validate.ts +88 -0
  267. package/src/dlp/composite-scanner.ts +213 -0
  268. package/src/dlp/index.ts +9 -0
  269. package/src/dlp/interfaces.ts +34 -0
  270. package/src/dlp/patterns.ts +30 -0
  271. package/src/dlp/prompt-injection-backend.ts +181 -0
  272. package/src/dlp/prompt-injection-patterns.ts +302 -0
  273. package/src/dlp/regex-backend.ts +181 -0
  274. package/src/dlp/scanner.ts +502 -0
  275. package/src/dlp/text-normalizer.ts +225 -0
  276. package/src/dlp/tool-patterns.ts +35 -0
  277. package/src/dlp/trufflehog-backend.ts +190 -0
  278. package/src/executor/filesystem-executor.ts +196 -0
  279. package/src/executor/http-executor.ts +349 -0
  280. package/src/executor/index.ts +9 -0
  281. package/src/executor/interfaces.ts +11 -0
  282. package/src/executor/noop-executor.ts +23 -0
  283. package/src/executor/registry.ts +64 -0
  284. package/src/executor/shell-executor.ts +148 -0
  285. package/src/executor/slack-executor.ts +176 -0
  286. package/src/executor/sql-executor.ts +146 -0
  287. package/src/executor/websocket-executor.ts +211 -0
  288. package/src/index.ts +24 -0
  289. package/src/interceptor/index.ts +1 -0
  290. package/src/interceptor/provider-interceptor.ts +315 -0
  291. package/src/mcp/auth-verifier.ts +152 -0
  292. package/src/mcp/bridge.ts +703 -0
  293. package/src/mcp/http-transport.ts +698 -0
  294. package/src/mcp/index.ts +9 -0
  295. package/src/mcp/internal-auth.ts +14 -0
  296. package/src/mcp/oauth-pages.ts +139 -0
  297. package/src/mcp/oauth-postgres-stores.ts +278 -0
  298. package/src/mcp/oauth-provider.ts +536 -0
  299. package/src/mcp/oauth-stores.ts +202 -0
  300. package/src/mcp/server.ts +55 -0
  301. package/src/mcp/tool-definitions.ts +562 -0
  302. package/src/metrics/collector.ts +357 -0
  303. package/src/metrics/index.ts +1 -0
  304. package/src/middleware/auth.ts +814 -0
  305. package/src/middleware/session.ts +85 -0
  306. package/src/middleware/validate.ts +130 -0
  307. package/src/policy/engine.ts +815 -0
  308. package/src/policy/index.ts +2 -0
  309. package/src/policy/opa-engine.ts +829 -0
  310. package/src/proxy/forward-proxy.ts +649 -0
  311. package/src/proxy/index.ts +1 -0
  312. package/src/ratelimit/limiter.ts +196 -0
  313. package/src/replay/engine.ts +142 -0
  314. package/src/replay/index.ts +1 -0
  315. package/src/saas/index.ts +1 -0
  316. package/src/saas/routes.ts +2178 -0
  317. package/src/server/app.ts +985 -0
  318. package/src/server/errors.ts +49 -0
  319. package/src/server/gateway.ts +1130 -0
  320. package/src/server/index.ts +307 -0
  321. package/src/server/logger.ts +255 -0
  322. package/src/server/stream-proxy.ts +202 -0
  323. package/src/storage/file-persistence.ts +315 -0
  324. package/src/storage/index.ts +4 -0
  325. package/src/storage/interfaces.ts +287 -0
  326. package/src/storage/memory.ts +686 -0
  327. package/src/storage/postgres.ts +1831 -0
  328. package/src/storage/redis.ts +835 -0
  329. package/src/tracing/index.ts +1 -0
  330. package/src/tracing/provider.ts +100 -0
  331. package/src/trust/calculator.ts +141 -0
  332. package/src/trust/index.ts +7 -0
  333. package/src/types/budget.ts +36 -0
  334. package/src/types/config.ts +278 -0
  335. package/src/types/events.ts +41 -0
  336. package/src/types/express.d.ts +14 -0
  337. package/src/types/index.ts +7 -0
  338. package/src/types/policy.ts +83 -0
  339. package/src/types/stripe-config.ts +11 -0
  340. package/src/types/subscription.ts +59 -0
  341. package/src/types/tool-call.ts +47 -0
  342. package/src/types/tool-result.ts +82 -0
  343. package/src/types/user.ts +125 -0
  344. package/tsconfig.json +24 -0
@@ -0,0 +1,686 @@
1
+ import { BudgetState } from '../types/budget';
2
+ import { AuditEvent, EventType } from '../types/events';
3
+ import { PolicyPack } from '../types/policy';
4
+ import {
5
+ User,
6
+ OAuthAccount,
7
+ OAuthProvider,
8
+ Workspace,
9
+ WorkspaceMember,
10
+ Session,
11
+ UserApiKey,
12
+ } from '../types/user';
13
+ import {
14
+ BudgetStore,
15
+ AuditStore,
16
+ ApprovalStore,
17
+ ApprovalRecord,
18
+ IdempotencyStore,
19
+ RateLimitStore,
20
+ UserStore,
21
+ OAuthAccountStore,
22
+ WorkspaceStore,
23
+ WorkspaceMemberStore,
24
+ SessionStore,
25
+ UserApiKeyStore,
26
+ SubscriptionStore,
27
+ PolicyStore,
28
+ RateLimitConfigStore,
29
+ BudgetConfigStore,
30
+ WorkspaceRateLimitConfig,
31
+ WorkspaceBudgetConfig,
32
+ } from './interfaces';
33
+ import { Subscription } from '../types/subscription';
34
+ import { ToolResult } from '../types/tool-result';
35
+
36
+ export class InMemoryBudgetStore implements BudgetStore {
37
+ private taskStates = new Map<string, BudgetState>();
38
+ private counters = new Map<string, number>();
39
+ private retryCounts = new Map<string, number>();
40
+
41
+ getTaskState(taskId: string): BudgetState | undefined {
42
+ return this.taskStates.get(taskId);
43
+ }
44
+
45
+ setTaskState(taskId: string, state: BudgetState): void {
46
+ this.taskStates.set(taskId, state);
47
+ }
48
+
49
+ getCounter(key: string): number {
50
+ return this.counters.get(key) ?? 0;
51
+ }
52
+
53
+ incrementCounter(key: string, amount: number): void {
54
+ this.counters.set(key, (this.counters.get(key) ?? 0) + amount);
55
+ }
56
+
57
+ getRetryCount(toolCallId: string): number {
58
+ return this.retryCounts.get(toolCallId) ?? 0;
59
+ }
60
+
61
+ incrementRetryCount(toolCallId: string): number {
62
+ const count = (this.retryCounts.get(toolCallId) ?? 0) + 1;
63
+ this.retryCounts.set(toolCallId, count);
64
+ return count;
65
+ }
66
+
67
+ async flush(): Promise<void> {}
68
+
69
+ reset(): void {
70
+ this.taskStates.clear();
71
+ this.counters.clear();
72
+ this.retryCounts.clear();
73
+ }
74
+ }
75
+
76
+ export class InMemoryAuditStore implements AuditStore {
77
+ private events: AuditEvent[] = [];
78
+
79
+ append(event: AuditEvent): void {
80
+ this.events.push(event);
81
+ }
82
+
83
+ getByTaskId(taskId: string): AuditEvent[] {
84
+ return this.events
85
+ .filter(e => e.task_id === taskId)
86
+ .sort((a, b) => a.timestamp.localeCompare(b.timestamp));
87
+ }
88
+
89
+ getByToolCallId(toolCallId: string): AuditEvent[] {
90
+ return this.events
91
+ .filter(e => e.tool_call_id === toolCallId)
92
+ .sort((a, b) => a.timestamp.localeCompare(b.timestamp));
93
+ }
94
+
95
+ getByEventType(eventType: EventType): AuditEvent[] {
96
+ return this.events.filter(e => e.event_type === eventType);
97
+ }
98
+
99
+ getAll(): AuditEvent[] {
100
+ return [...this.events];
101
+ }
102
+
103
+ deleteByTaskId(taskId: string): void {
104
+ this.events = this.events.filter(e => e.task_id !== taskId);
105
+ }
106
+
107
+ deleteBySessionId(sessionId: string): void {
108
+ this.events = this.events.filter(e => e.session_id !== sessionId);
109
+ }
110
+
111
+ clear(): void {
112
+ this.events = [];
113
+ }
114
+ }
115
+
116
+ export class InMemoryApprovalStore implements ApprovalStore {
117
+ private approvals = new Map<string, ApprovalRecord>();
118
+ private tokenIndex = new Map<string, string>();
119
+
120
+ save(approvalId: string, approval: ApprovalRecord): void {
121
+ this.approvals.set(approvalId, approval);
122
+ }
123
+
124
+ getById(approvalId: string): ApprovalRecord | undefined {
125
+ return this.approvals.get(approvalId);
126
+ }
127
+
128
+ getByToken(token: string): ApprovalRecord | undefined {
129
+ const id = this.tokenIndex.get(token);
130
+ return id ? this.approvals.get(id) : undefined;
131
+ }
132
+
133
+ getByToolCallId(toolCallId: string): ApprovalRecord | undefined {
134
+ for (const approval of this.approvals.values()) {
135
+ if (approval.tool_call_id === toolCallId) return approval;
136
+ }
137
+ return undefined;
138
+ }
139
+
140
+ findApproved(taskId: string, actorId: string, toolName: string, capability: string): ApprovalRecord | undefined {
141
+ for (const approval of this.approvals.values()) {
142
+ if (approval.status !== 'approved') continue;
143
+ if (approval.task_id !== taskId) continue;
144
+ if (approval.actor_id !== actorId) continue;
145
+ if (approval.tool_name === toolName || approval.tool_capability === capability) {
146
+ return approval;
147
+ }
148
+ }
149
+ return undefined;
150
+ }
151
+
152
+ findPending(workspaceId?: string): ApprovalRecord[] {
153
+ const results: ApprovalRecord[] = [];
154
+ for (const approval of this.approvals.values()) {
155
+ if (approval.status !== 'pending') continue;
156
+ if (workspaceId && approval.workspace_id !== workspaceId) continue;
157
+ results.push(approval);
158
+ }
159
+ return results;
160
+ }
161
+
162
+ indexToken(token: string, approvalId: string): void {
163
+ this.tokenIndex.set(token, approvalId);
164
+ }
165
+
166
+ compareAndSetStatus(approvalId: string, expectedStatus: string, approval: ApprovalRecord): boolean {
167
+ const existing = this.approvals.get(approvalId);
168
+ if (!existing || existing.status !== expectedStatus) return false;
169
+ this.approvals.set(approvalId, approval);
170
+ return true;
171
+ }
172
+
173
+ async flush(): Promise<void> {}
174
+
175
+ clear(): void {
176
+ this.approvals.clear();
177
+ this.tokenIndex.clear();
178
+ }
179
+ }
180
+
181
+ export class InMemoryIdempotencyStore implements IdempotencyStore {
182
+ private entries = new Map<string, { result: ToolResult; expiresAt: number }>();
183
+ private lastEviction = Date.now();
184
+ /** Evict expired entries every 30 seconds or when cache exceeds 5000 entries */
185
+ private static readonly EVICTION_INTERVAL_MS = 30000;
186
+ private static readonly MAX_ENTRIES = 5000;
187
+
188
+ async get(toolCallId: string): Promise<ToolResult | undefined> {
189
+ const entry = this.entries.get(toolCallId);
190
+ if (!entry) return undefined;
191
+ if (Date.now() > entry.expiresAt) {
192
+ this.entries.delete(toolCallId);
193
+ return undefined;
194
+ }
195
+ return entry.result;
196
+ }
197
+
198
+ set(toolCallId: string, result: ToolResult, ttlMs: number): void {
199
+ this.entries.set(toolCallId, {
200
+ result,
201
+ expiresAt: Date.now() + ttlMs,
202
+ });
203
+ this.maybeEvict();
204
+ }
205
+
206
+ /** Proactively evict expired entries based on time or size thresholds */
207
+ private maybeEvict(): void {
208
+ const now = Date.now();
209
+ const shouldEvict = this.entries.size > InMemoryIdempotencyStore.MAX_ENTRIES
210
+ || (now - this.lastEviction) > InMemoryIdempotencyStore.EVICTION_INTERVAL_MS;
211
+
212
+ if (shouldEvict) {
213
+ for (const [key, val] of this.entries) {
214
+ if (now > val.expiresAt) this.entries.delete(key);
215
+ }
216
+ this.lastEviction = now;
217
+ }
218
+ }
219
+
220
+ async has(toolCallId: string): Promise<boolean> {
221
+ return (await this.get(toolCallId)) !== undefined;
222
+ }
223
+
224
+ async flush(): Promise<void> {}
225
+
226
+ clear(): void {
227
+ this.entries.clear();
228
+ }
229
+ }
230
+
231
+ export class InMemoryRateLimitStore implements RateLimitStore {
232
+ // Sliding window counters: key -> array of timestamps
233
+ private windows = new Map<string, number[]>();
234
+
235
+ hit(key: string, windowMs: number, maxRequests: number): {
236
+ allowed: boolean;
237
+ current: number;
238
+ limit: number;
239
+ resetAt: number;
240
+ } {
241
+ const now = Date.now();
242
+ const cutoff = now - windowMs;
243
+
244
+ // Get existing timestamps and prune expired ones
245
+ let timestamps = this.windows.get(key) || [];
246
+ timestamps = timestamps.filter(t => t > cutoff);
247
+
248
+ // Add current hit
249
+ timestamps.push(now);
250
+ this.windows.set(key, timestamps);
251
+
252
+ const current = timestamps.length;
253
+ const allowed = current <= maxRequests;
254
+ const resetAt = timestamps.length > 0 ? timestamps[0] + windowMs : now + windowMs;
255
+
256
+ return { allowed, current, limit: maxRequests, resetAt };
257
+ }
258
+
259
+ reset(): void {
260
+ this.windows.clear();
261
+ }
262
+ }
263
+
264
+ // ---------------------------------------------------------------------------
265
+ // SaaS In-Memory Stores
266
+ // ---------------------------------------------------------------------------
267
+
268
+ export class InMemoryUserStore implements UserStore {
269
+ private users = new Map<string, User>();
270
+
271
+ create(user: User): void {
272
+ this.users.set(user.id, { ...user });
273
+ }
274
+
275
+ getById(id: string): User | undefined {
276
+ const u = this.users.get(id);
277
+ return u ? { ...u } : undefined;
278
+ }
279
+
280
+ getByEmail(email: string): User | undefined {
281
+ for (const u of this.users.values()) {
282
+ if (u.email === email) return { ...u };
283
+ }
284
+ return undefined;
285
+ }
286
+
287
+ update(id: string, updates: Partial<Pick<User, 'display_name' | 'avatar_url' | 'password_hash' | 'status' | 'onboarding_completed' | 'updated_at'>>): User | undefined {
288
+ const u = this.users.get(id);
289
+ if (!u) return undefined;
290
+ Object.assign(u, updates);
291
+ return { ...u };
292
+ }
293
+
294
+ delete(id: string): boolean {
295
+ return this.users.delete(id);
296
+ }
297
+
298
+ list(): User[] {
299
+ return Array.from(this.users.values()).map(u => ({ ...u }));
300
+ }
301
+ }
302
+
303
+ export class InMemoryOAuthAccountStore implements OAuthAccountStore {
304
+ private accounts = new Map<string, OAuthAccount>();
305
+
306
+ create(account: OAuthAccount): void {
307
+ this.accounts.set(account.id, { ...account });
308
+ }
309
+
310
+ getById(id: string): OAuthAccount | undefined {
311
+ const a = this.accounts.get(id);
312
+ return a ? { ...a } : undefined;
313
+ }
314
+
315
+ getByProvider(provider: OAuthProvider, providerUserId: string): OAuthAccount | undefined {
316
+ for (const a of this.accounts.values()) {
317
+ if (a.provider === provider && a.provider_user_id === providerUserId) return { ...a };
318
+ }
319
+ return undefined;
320
+ }
321
+
322
+ getByUserId(userId: string): OAuthAccount[] {
323
+ const results: OAuthAccount[] = [];
324
+ for (const a of this.accounts.values()) {
325
+ if (a.user_id === userId) results.push({ ...a });
326
+ }
327
+ return results;
328
+ }
329
+
330
+ update(id: string, updates: Partial<Pick<OAuthAccount, 'access_token_encrypted' | 'refresh_token_encrypted' | 'token_expires_at' | 'updated_at'>>): OAuthAccount | undefined {
331
+ const a = this.accounts.get(id);
332
+ if (!a) return undefined;
333
+ Object.assign(a, updates);
334
+ return { ...a };
335
+ }
336
+
337
+ delete(id: string): boolean {
338
+ return this.accounts.delete(id);
339
+ }
340
+ }
341
+
342
+ export class InMemoryWorkspaceStore implements WorkspaceStore {
343
+ private workspaces = new Map<string, Workspace>();
344
+
345
+ create(workspace: Workspace): void {
346
+ this.workspaces.set(workspace.id, { ...workspace });
347
+ }
348
+
349
+ getById(id: string): Workspace | undefined {
350
+ const w = this.workspaces.get(id);
351
+ return w ? { ...w } : undefined;
352
+ }
353
+
354
+ getBySlug(slug: string): Workspace | undefined {
355
+ for (const w of this.workspaces.values()) {
356
+ if (w.slug === slug) return { ...w };
357
+ }
358
+ return undefined;
359
+ }
360
+
361
+ getByOwner(userId: string): Workspace[] {
362
+ const results: Workspace[] = [];
363
+ for (const w of this.workspaces.values()) {
364
+ if (w.owner_user_id === userId) results.push({ ...w });
365
+ }
366
+ return results;
367
+ }
368
+
369
+ update(id: string, updates: Partial<Pick<Workspace, 'name' | 'slug' | 'plan' | 'settings' | 'updated_at'>>): Workspace | undefined {
370
+ const w = this.workspaces.get(id);
371
+ if (!w) return undefined;
372
+ Object.assign(w, updates);
373
+ return { ...w };
374
+ }
375
+
376
+ delete(id: string): boolean {
377
+ return this.workspaces.delete(id);
378
+ }
379
+
380
+ list(): Workspace[] {
381
+ return Array.from(this.workspaces.values()).map(w => ({ ...w }));
382
+ }
383
+ }
384
+
385
+ export class InMemoryWorkspaceMemberStore implements WorkspaceMemberStore {
386
+ private members = new Map<string, WorkspaceMember>();
387
+
388
+ create(member: WorkspaceMember): void {
389
+ this.members.set(member.id, { ...member });
390
+ }
391
+
392
+ getById(id: string): WorkspaceMember | undefined {
393
+ const m = this.members.get(id);
394
+ return m ? { ...m } : undefined;
395
+ }
396
+
397
+ getByWorkspace(workspaceId: string): WorkspaceMember[] {
398
+ const results: WorkspaceMember[] = [];
399
+ for (const m of this.members.values()) {
400
+ if (m.workspace_id === workspaceId) results.push({ ...m });
401
+ }
402
+ return results;
403
+ }
404
+
405
+ getByUser(userId: string): WorkspaceMember[] {
406
+ const results: WorkspaceMember[] = [];
407
+ for (const m of this.members.values()) {
408
+ if (m.user_id === userId) results.push({ ...m });
409
+ }
410
+ return results;
411
+ }
412
+
413
+ getByWorkspaceAndUser(workspaceId: string, userId: string): WorkspaceMember | undefined {
414
+ for (const m of this.members.values()) {
415
+ if (m.workspace_id === workspaceId && m.user_id === userId) return { ...m };
416
+ }
417
+ return undefined;
418
+ }
419
+
420
+ update(id: string, updates: Partial<Pick<WorkspaceMember, 'role'>>): WorkspaceMember | undefined {
421
+ const m = this.members.get(id);
422
+ if (!m) return undefined;
423
+ Object.assign(m, updates);
424
+ return { ...m };
425
+ }
426
+
427
+ delete(id: string): boolean {
428
+ return this.members.delete(id);
429
+ }
430
+ }
431
+
432
+ export class InMemorySessionStore implements SessionStore {
433
+ private sessions = new Map<string, Session>();
434
+
435
+ create(session: Session): void {
436
+ this.sessions.set(session.id, { ...session });
437
+ }
438
+
439
+ getById(id: string): Session | undefined {
440
+ const s = this.sessions.get(id);
441
+ if (!s) return undefined;
442
+ // Check expiry
443
+ if (new Date(s.expires_at).getTime() <= Date.now()) {
444
+ this.sessions.delete(id);
445
+ return undefined;
446
+ }
447
+ return { ...s };
448
+ }
449
+
450
+ getByUserId(userId: string): Session[] {
451
+ const now = Date.now();
452
+ const results: Session[] = [];
453
+ for (const s of this.sessions.values()) {
454
+ if (s.user_id === userId && new Date(s.expires_at).getTime() > now) {
455
+ results.push({ ...s });
456
+ }
457
+ }
458
+ return results;
459
+ }
460
+
461
+ update(id: string, updates: Partial<Pick<Session, 'workspace_id' | 'last_active_at'>>): Session | undefined {
462
+ const s = this.sessions.get(id);
463
+ if (!s) return undefined;
464
+ Object.assign(s, updates);
465
+ return { ...s };
466
+ }
467
+
468
+ delete(id: string): boolean {
469
+ return this.sessions.delete(id);
470
+ }
471
+
472
+ deleteExpired(): number {
473
+ const now = Date.now();
474
+ let count = 0;
475
+ for (const [id, s] of this.sessions) {
476
+ if (new Date(s.expires_at).getTime() <= now) {
477
+ this.sessions.delete(id);
478
+ count++;
479
+ }
480
+ }
481
+ return count;
482
+ }
483
+
484
+ deleteByUserId(userId: string): number {
485
+ let count = 0;
486
+ for (const [id, s] of this.sessions) {
487
+ if (s.user_id === userId) {
488
+ this.sessions.delete(id);
489
+ count++;
490
+ }
491
+ }
492
+ return count;
493
+ }
494
+ }
495
+
496
+ export class InMemoryUserApiKeyStore implements UserApiKeyStore {
497
+ private keys = new Map<string, UserApiKey>();
498
+
499
+ create(apiKey: UserApiKey): void {
500
+ this.keys.set(apiKey.id, { ...apiKey });
501
+ }
502
+
503
+ getById(id: string): UserApiKey | undefined {
504
+ const k = this.keys.get(id);
505
+ return k ? { ...k } : undefined;
506
+ }
507
+
508
+ getByKeyHash(keyHash: string): UserApiKey | undefined {
509
+ for (const k of this.keys.values()) {
510
+ if (k.key_hash === keyHash) return { ...k };
511
+ }
512
+ return undefined;
513
+ }
514
+
515
+ verifyToken(token: string): UserApiKey | undefined {
516
+ const crypto = require('crypto') as typeof import('crypto');
517
+ const unsaltedHash = crypto.createHash('sha256').update(token).digest('hex');
518
+
519
+ for (const k of this.keys.values()) {
520
+ if (k.key_hash.includes(':')) {
521
+ // Salted format: "salt:hash"
522
+ const colonIndex = k.key_hash.indexOf(':');
523
+ const salt = k.key_hash.slice(0, colonIndex);
524
+ const expectedHash = k.key_hash.slice(colonIndex + 1);
525
+ const computedHash = crypto.createHash('sha256').update(salt + token).digest('hex');
526
+ const a = Buffer.from(computedHash, 'hex');
527
+ const b = Buffer.from(expectedHash, 'hex');
528
+ if (a.length === b.length && crypto.timingSafeEqual(a, b)) {
529
+ return { ...k };
530
+ }
531
+ } else {
532
+ // Legacy unsalted format
533
+ if (k.key_hash === unsaltedHash) return { ...k };
534
+ }
535
+ }
536
+ return undefined;
537
+ }
538
+
539
+ getByWorkspace(workspaceId: string): UserApiKey[] {
540
+ const results: UserApiKey[] = [];
541
+ for (const k of this.keys.values()) {
542
+ if (k.workspace_id === workspaceId) results.push({ ...k });
543
+ }
544
+ return results;
545
+ }
546
+
547
+ getByUser(userId: string): UserApiKey[] {
548
+ const results: UserApiKey[] = [];
549
+ for (const k of this.keys.values()) {
550
+ if (k.user_id === userId) results.push({ ...k });
551
+ }
552
+ return results;
553
+ }
554
+
555
+ update(id: string, updates: Partial<Pick<UserApiKey, 'name' | 'roles' | 'tags' | 'revoked' | 'last_used_at'>>): UserApiKey | undefined {
556
+ const k = this.keys.get(id);
557
+ if (!k) return undefined;
558
+ Object.assign(k, updates);
559
+ return { ...k };
560
+ }
561
+
562
+ delete(id: string): boolean {
563
+ return this.keys.delete(id);
564
+ }
565
+ }
566
+
567
+ export class InMemorySubscriptionStore implements SubscriptionStore {
568
+ private subscriptions = new Map<string, Subscription>();
569
+
570
+ create(subscription: Subscription): void {
571
+ this.subscriptions.set(subscription.id, { ...subscription });
572
+ }
573
+
574
+ getById(id: string): Subscription | undefined {
575
+ const s = this.subscriptions.get(id);
576
+ return s ? { ...s } : undefined;
577
+ }
578
+
579
+ getByWorkspace(workspaceId: string): Subscription | undefined {
580
+ for (const s of this.subscriptions.values()) {
581
+ if (s.workspace_id === workspaceId) return { ...s };
582
+ }
583
+ return undefined;
584
+ }
585
+
586
+ getByStripeCustomerId(customerId: string): Subscription | undefined {
587
+ for (const s of this.subscriptions.values()) {
588
+ if (s.stripe_customer_id === customerId) return { ...s };
589
+ }
590
+ return undefined;
591
+ }
592
+
593
+ getByStripeSubscriptionId(subscriptionId: string): Subscription | undefined {
594
+ for (const s of this.subscriptions.values()) {
595
+ if (s.stripe_subscription_id === subscriptionId) return { ...s };
596
+ }
597
+ return undefined;
598
+ }
599
+
600
+ update(id: string, updates: Partial<Subscription>): Subscription | undefined {
601
+ const s = this.subscriptions.get(id);
602
+ if (!s) return undefined;
603
+ Object.assign(s, updates);
604
+ return { ...s };
605
+ }
606
+
607
+ delete(id: string): boolean {
608
+ return this.subscriptions.delete(id);
609
+ }
610
+
611
+ list(): Subscription[] {
612
+ return Array.from(this.subscriptions.values()).map(s => ({ ...s }));
613
+ }
614
+ }
615
+
616
+ export class InMemoryPolicyStore implements PolicyStore {
617
+ private policies = new Map<string, PolicyPack>();
618
+
619
+ getByWorkspaceId(workspaceId: string): PolicyPack | undefined {
620
+ return this.policies.get(workspaceId);
621
+ }
622
+
623
+ set(workspaceId: string, policy: PolicyPack): void {
624
+ this.policies.set(workspaceId, policy);
625
+ }
626
+
627
+ delete(workspaceId: string): boolean {
628
+ return this.policies.delete(workspaceId);
629
+ }
630
+
631
+ list(): Map<string, PolicyPack> {
632
+ return new Map(this.policies);
633
+ }
634
+
635
+ clear(): void {
636
+ this.policies.clear();
637
+ }
638
+ }
639
+
640
+ export class InMemoryRateLimitConfigStore implements RateLimitConfigStore {
641
+ private configs = new Map<string, WorkspaceRateLimitConfig>();
642
+
643
+ getByWorkspaceId(workspaceId: string): WorkspaceRateLimitConfig | undefined {
644
+ return this.configs.get(workspaceId);
645
+ }
646
+
647
+ set(workspaceId: string, config: WorkspaceRateLimitConfig): void {
648
+ this.configs.set(workspaceId, config);
649
+ }
650
+
651
+ delete(workspaceId: string): boolean {
652
+ return this.configs.delete(workspaceId);
653
+ }
654
+
655
+ list(): Map<string, WorkspaceRateLimitConfig> {
656
+ return new Map(this.configs);
657
+ }
658
+
659
+ clear(): void {
660
+ this.configs.clear();
661
+ }
662
+ }
663
+
664
+ export class InMemoryBudgetConfigStore implements BudgetConfigStore {
665
+ private configs = new Map<string, WorkspaceBudgetConfig>();
666
+
667
+ getByWorkspaceId(workspaceId: string): WorkspaceBudgetConfig | undefined {
668
+ return this.configs.get(workspaceId);
669
+ }
670
+
671
+ set(workspaceId: string, config: WorkspaceBudgetConfig): void {
672
+ this.configs.set(workspaceId, config);
673
+ }
674
+
675
+ delete(workspaceId: string): boolean {
676
+ return this.configs.delete(workspaceId);
677
+ }
678
+
679
+ list(): Map<string, WorkspaceBudgetConfig> {
680
+ return new Map(this.configs);
681
+ }
682
+
683
+ clear(): void {
684
+ this.configs.clear();
685
+ }
686
+ }