mcp-creatio 0.3.6

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 (370) hide show
  1. package/.dockerignore +12 -0
  2. package/.editorconfig +14 -0
  3. package/.eslintrc.cjs +18 -0
  4. package/.gitattributes +8 -0
  5. package/.github/workflows/docker-publish.yml +50 -0
  6. package/.prettierignore +3 -0
  7. package/.prettierrc +9 -0
  8. package/.vscode/launch.json +23 -0
  9. package/.vscode/mcp.json +13 -0
  10. package/.vscode/settings.json +16 -0
  11. package/Agent.md +187 -0
  12. package/Debug.md +32 -0
  13. package/Dockerfile +23 -0
  14. package/LICENSE +21 -0
  15. package/README.md +162 -0
  16. package/dist/cli.d.ts +3 -0
  17. package/dist/cli.d.ts.map +1 -0
  18. package/dist/cli.js +135 -0
  19. package/dist/cli.js.map +1 -0
  20. package/dist/config-builder.d.ts +3 -0
  21. package/dist/config-builder.d.ts.map +1 -0
  22. package/dist/config-builder.js +66 -0
  23. package/dist/config-builder.js.map +1 -0
  24. package/dist/consts.d.ts +2 -0
  25. package/dist/consts.d.ts.map +1 -0
  26. package/dist/consts.js +6 -0
  27. package/dist/consts.js.map +1 -0
  28. package/dist/creatio/auth/auth-manager.d.ts +9 -0
  29. package/dist/creatio/auth/auth-manager.d.ts.map +1 -0
  30. package/dist/creatio/auth/auth-manager.js +29 -0
  31. package/dist/creatio/auth/auth-manager.js.map +1 -0
  32. package/dist/creatio/auth/auth.d.ts +16 -0
  33. package/dist/creatio/auth/auth.d.ts.map +1 -0
  34. package/dist/creatio/auth/auth.js +20 -0
  35. package/dist/creatio/auth/auth.js.map +1 -0
  36. package/dist/creatio/auth/index.d.ts +4 -0
  37. package/dist/creatio/auth/index.d.ts.map +1 -0
  38. package/dist/creatio/auth/index.js +21 -0
  39. package/dist/creatio/auth/index.js.map +1 -0
  40. package/dist/creatio/auth/providers/base-oauth2-provider.d.ts +17 -0
  41. package/dist/creatio/auth/providers/base-oauth2-provider.d.ts.map +1 -0
  42. package/dist/creatio/auth/providers/base-oauth2-provider.js +49 -0
  43. package/dist/creatio/auth/providers/base-oauth2-provider.js.map +1 -0
  44. package/dist/creatio/auth/providers/base-provider.d.ts +15 -0
  45. package/dist/creatio/auth/providers/base-provider.d.ts.map +1 -0
  46. package/dist/creatio/auth/providers/base-provider.js +32 -0
  47. package/dist/creatio/auth/providers/base-provider.js.map +1 -0
  48. package/dist/creatio/auth/providers/index.d.ts +5 -0
  49. package/dist/creatio/auth/providers/index.d.ts.map +1 -0
  50. package/dist/creatio/auth/providers/index.js +21 -0
  51. package/dist/creatio/auth/providers/index.js.map +1 -0
  52. package/dist/creatio/auth/providers/legacy-provider.d.ts +10 -0
  53. package/dist/creatio/auth/providers/legacy-provider.d.ts.map +1 -0
  54. package/dist/creatio/auth/providers/legacy-provider.js +73 -0
  55. package/dist/creatio/auth/providers/legacy-provider.js.map +1 -0
  56. package/dist/creatio/auth/providers/oauth2-code-provider.d.ts +18 -0
  57. package/dist/creatio/auth/providers/oauth2-code-provider.d.ts.map +1 -0
  58. package/dist/creatio/auth/providers/oauth2-code-provider.js +245 -0
  59. package/dist/creatio/auth/providers/oauth2-code-provider.js.map +1 -0
  60. package/dist/creatio/auth/providers/oauth2-provider.d.ts +9 -0
  61. package/dist/creatio/auth/providers/oauth2-provider.d.ts.map +1 -0
  62. package/dist/creatio/auth/providers/oauth2-provider.js +86 -0
  63. package/dist/creatio/auth/providers/oauth2-provider.js.map +1 -0
  64. package/dist/creatio/auth/providers/type.d.ts +6 -0
  65. package/dist/creatio/auth/providers/type.d.ts.map +1 -0
  66. package/dist/creatio/auth/providers/type.js +10 -0
  67. package/dist/creatio/auth/providers/type.js.map +1 -0
  68. package/dist/creatio/client-config.d.ts +29 -0
  69. package/dist/creatio/client-config.d.ts.map +1 -0
  70. package/dist/creatio/client-config.js +3 -0
  71. package/dist/creatio/client-config.js.map +1 -0
  72. package/dist/creatio/engines/crud/crud-engine.d.ts +15 -0
  73. package/dist/creatio/engines/crud/crud-engine.d.ts.map +1 -0
  74. package/dist/creatio/engines/crud/crud-engine.js +33 -0
  75. package/dist/creatio/engines/crud/crud-engine.js.map +1 -0
  76. package/dist/creatio/engines/engine-manager.d.ts +33 -0
  77. package/dist/creatio/engines/engine-manager.d.ts.map +1 -0
  78. package/dist/creatio/engines/engine-manager.js +54 -0
  79. package/dist/creatio/engines/engine-manager.js.map +1 -0
  80. package/dist/creatio/engines/engine-registry.d.ts +15 -0
  81. package/dist/creatio/engines/engine-registry.d.ts.map +1 -0
  82. package/dist/creatio/engines/engine-registry.js +35 -0
  83. package/dist/creatio/engines/engine-registry.js.map +1 -0
  84. package/dist/creatio/engines/engine.d.ts +4 -0
  85. package/dist/creatio/engines/engine.d.ts.map +1 -0
  86. package/dist/creatio/engines/engine.js +3 -0
  87. package/dist/creatio/engines/engine.js.map +1 -0
  88. package/dist/creatio/engines/index.d.ts +8 -0
  89. package/dist/creatio/engines/index.d.ts.map +1 -0
  90. package/dist/creatio/engines/index.js +24 -0
  91. package/dist/creatio/engines/index.js.map +1 -0
  92. package/dist/creatio/engines/process/process-engine.d.ts +10 -0
  93. package/dist/creatio/engines/process/process-engine.d.ts.map +1 -0
  94. package/dist/creatio/engines/process/process-engine.js +18 -0
  95. package/dist/creatio/engines/process/process-engine.js.map +1 -0
  96. package/dist/creatio/engines/sys-settings/sys-settings-engine.d.ts +13 -0
  97. package/dist/creatio/engines/sys-settings/sys-settings-engine.d.ts.map +1 -0
  98. package/dist/creatio/engines/sys-settings/sys-settings-engine.js +27 -0
  99. package/dist/creatio/engines/sys-settings/sys-settings-engine.js.map +1 -0
  100. package/dist/creatio/engines/user/user-engine.d.ts +10 -0
  101. package/dist/creatio/engines/user/user-engine.d.ts.map +1 -0
  102. package/dist/creatio/engines/user/user-engine.js +18 -0
  103. package/dist/creatio/engines/user/user-engine.js.map +1 -0
  104. package/dist/creatio/index.d.ts +7 -0
  105. package/dist/creatio/index.d.ts.map +1 -0
  106. package/dist/creatio/index.js +23 -0
  107. package/dist/creatio/index.js.map +1 -0
  108. package/dist/creatio/provider-context.d.ts +10 -0
  109. package/dist/creatio/provider-context.d.ts.map +1 -0
  110. package/dist/creatio/provider-context.js +3 -0
  111. package/dist/creatio/provider-context.js.map +1 -0
  112. package/dist/creatio/providers/crud-provider.d.ts +40 -0
  113. package/dist/creatio/providers/crud-provider.d.ts.map +1 -0
  114. package/dist/creatio/providers/crud-provider.js +3 -0
  115. package/dist/creatio/providers/crud-provider.js.map +1 -0
  116. package/dist/creatio/providers/index.d.ts +5 -0
  117. package/dist/creatio/providers/index.d.ts.map +1 -0
  118. package/dist/creatio/providers/index.js +21 -0
  119. package/dist/creatio/providers/index.js.map +1 -0
  120. package/dist/creatio/providers/process-provider.d.ts +14 -0
  121. package/dist/creatio/providers/process-provider.d.ts.map +1 -0
  122. package/dist/creatio/providers/process-provider.js +3 -0
  123. package/dist/creatio/providers/process-provider.js.map +1 -0
  124. package/dist/creatio/providers/sys-settings-provider.d.ts +58 -0
  125. package/dist/creatio/providers/sys-settings-provider.d.ts.map +1 -0
  126. package/dist/creatio/providers/sys-settings-provider.js +3 -0
  127. package/dist/creatio/providers/sys-settings-provider.js.map +1 -0
  128. package/dist/creatio/providers/user-provider.d.ts +12 -0
  129. package/dist/creatio/providers/user-provider.d.ts.map +1 -0
  130. package/dist/creatio/providers/user-provider.js +3 -0
  131. package/dist/creatio/providers/user-provider.js.map +1 -0
  132. package/dist/creatio/services/creatio-service-context.d.ts +17 -0
  133. package/dist/creatio/services/creatio-service-context.d.ts.map +1 -0
  134. package/dist/creatio/services/creatio-service-context.js +35 -0
  135. package/dist/creatio/services/creatio-service-context.js.map +1 -0
  136. package/dist/creatio/services/http-client.d.ts +29 -0
  137. package/dist/creatio/services/http-client.d.ts.map +1 -0
  138. package/dist/creatio/services/http-client.js +136 -0
  139. package/dist/creatio/services/http-client.js.map +1 -0
  140. package/dist/creatio/services/index.d.ts +8 -0
  141. package/dist/creatio/services/index.d.ts.map +1 -0
  142. package/dist/creatio/services/index.js +24 -0
  143. package/dist/creatio/services/index.js.map +1 -0
  144. package/dist/creatio/services/metadata-store.d.ts +20 -0
  145. package/dist/creatio/services/metadata-store.d.ts.map +1 -0
  146. package/dist/creatio/services/metadata-store.js +162 -0
  147. package/dist/creatio/services/metadata-store.js.map +1 -0
  148. package/dist/creatio/services/odata-crud-provider.d.ts +21 -0
  149. package/dist/creatio/services/odata-crud-provider.d.ts.map +1 -0
  150. package/dist/creatio/services/odata-crud-provider.js +145 -0
  151. package/dist/creatio/services/odata-crud-provider.js.map +1 -0
  152. package/dist/creatio/services/process-service-provider.d.ts +11 -0
  153. package/dist/creatio/services/process-service-provider.d.ts.map +1 -0
  154. package/dist/creatio/services/process-service-provider.js +52 -0
  155. package/dist/creatio/services/process-service-provider.js.map +1 -0
  156. package/dist/creatio/services/sys-settings-service-provider.d.ts +19 -0
  157. package/dist/creatio/services/sys-settings-service-provider.d.ts.map +1 -0
  158. package/dist/creatio/services/sys-settings-service-provider.js +107 -0
  159. package/dist/creatio/services/sys-settings-service-provider.js.map +1 -0
  160. package/dist/creatio/services/user-info-provider.d.ts +10 -0
  161. package/dist/creatio/services/user-info-provider.d.ts.map +1 -0
  162. package/dist/creatio/services/user-info-provider.js +26 -0
  163. package/dist/creatio/services/user-info-provider.js.map +1 -0
  164. package/dist/index.d.ts +2 -0
  165. package/dist/index.d.ts.map +1 -0
  166. package/dist/index.js +46 -0
  167. package/dist/index.js.map +1 -0
  168. package/dist/log.d.ts +51 -0
  169. package/dist/log.d.ts.map +1 -0
  170. package/dist/log.js +137 -0
  171. package/dist/log.js.map +1 -0
  172. package/dist/server/http/creatio-oauth-handlers.d.ts +14 -0
  173. package/dist/server/http/creatio-oauth-handlers.d.ts.map +1 -0
  174. package/dist/server/http/creatio-oauth-handlers.js +137 -0
  175. package/dist/server/http/creatio-oauth-handlers.js.map +1 -0
  176. package/dist/server/http/httpServer.d.ts +23 -0
  177. package/dist/server/http/httpServer.d.ts.map +1 -0
  178. package/dist/server/http/httpServer.js +131 -0
  179. package/dist/server/http/httpServer.js.map +1 -0
  180. package/dist/server/http/index.d.ts +6 -0
  181. package/dist/server/http/index.d.ts.map +1 -0
  182. package/dist/server/http/index.js +22 -0
  183. package/dist/server/http/index.js.map +1 -0
  184. package/dist/server/http/mcp-handlers.d.ts +10 -0
  185. package/dist/server/http/mcp-handlers.d.ts.map +1 -0
  186. package/dist/server/http/mcp-handlers.js +82 -0
  187. package/dist/server/http/mcp-handlers.js.map +1 -0
  188. package/dist/server/http/mcp-oauth-handlers.d.ts +11 -0
  189. package/dist/server/http/mcp-oauth-handlers.d.ts.map +1 -0
  190. package/dist/server/http/mcp-oauth-handlers.js +106 -0
  191. package/dist/server/http/mcp-oauth-handlers.js.map +1 -0
  192. package/dist/server/http/middleware.d.ts +11 -0
  193. package/dist/server/http/middleware.d.ts.map +1 -0
  194. package/dist/server/http/middleware.js +88 -0
  195. package/dist/server/http/middleware.js.map +1 -0
  196. package/dist/server/index.d.ts +3 -0
  197. package/dist/server/index.d.ts.map +1 -0
  198. package/dist/server/index.js +19 -0
  199. package/dist/server/index.js.map +1 -0
  200. package/dist/server/mcp/filters.d.ts +2 -0
  201. package/dist/server/mcp/filters.d.ts.map +1 -0
  202. package/dist/server/mcp/filters.js +94 -0
  203. package/dist/server/mcp/filters.js.map +1 -0
  204. package/dist/server/mcp/index.d.ts +2 -0
  205. package/dist/server/mcp/index.d.ts.map +1 -0
  206. package/dist/server/mcp/index.js +18 -0
  207. package/dist/server/mcp/index.js.map +1 -0
  208. package/dist/server/mcp/prompts-data.d.ts +147 -0
  209. package/dist/server/mcp/prompts-data.d.ts.map +1 -0
  210. package/dist/server/mcp/prompts-data.js +884 -0
  211. package/dist/server/mcp/prompts-data.js.map +1 -0
  212. package/dist/server/mcp/server.d.ts +25 -0
  213. package/dist/server/mcp/server.d.ts.map +1 -0
  214. package/dist/server/mcp/server.js +233 -0
  215. package/dist/server/mcp/server.js.map +1 -0
  216. package/dist/server/mcp/tools-data.d.ts +165 -0
  217. package/dist/server/mcp/tools-data.d.ts.map +1 -0
  218. package/dist/server/mcp/tools-data.js +466 -0
  219. package/dist/server/mcp/tools-data.js.map +1 -0
  220. package/dist/server/oauth/client-manager.d.ts +6 -0
  221. package/dist/server/oauth/client-manager.d.ts.map +1 -0
  222. package/dist/server/oauth/client-manager.js +52 -0
  223. package/dist/server/oauth/client-manager.js.map +1 -0
  224. package/dist/server/oauth/index.d.ts +7 -0
  225. package/dist/server/oauth/index.d.ts.map +1 -0
  226. package/dist/server/oauth/index.js +23 -0
  227. package/dist/server/oauth/index.js.map +1 -0
  228. package/dist/server/oauth/oauth-server.d.ts +21 -0
  229. package/dist/server/oauth/oauth-server.d.ts.map +1 -0
  230. package/dist/server/oauth/oauth-server.js +146 -0
  231. package/dist/server/oauth/oauth-server.js.map +1 -0
  232. package/dist/server/oauth/storage.d.ts +31 -0
  233. package/dist/server/oauth/storage.d.ts.map +1 -0
  234. package/dist/server/oauth/storage.js +73 -0
  235. package/dist/server/oauth/storage.js.map +1 -0
  236. package/dist/server/oauth/token-manager.d.ts +13 -0
  237. package/dist/server/oauth/token-manager.d.ts.map +1 -0
  238. package/dist/server/oauth/token-manager.js +69 -0
  239. package/dist/server/oauth/token-manager.js.map +1 -0
  240. package/dist/server/oauth/types.d.ts +51 -0
  241. package/dist/server/oauth/types.d.ts.map +1 -0
  242. package/dist/server/oauth/types.js +3 -0
  243. package/dist/server/oauth/types.js.map +1 -0
  244. package/dist/server/oauth/validators.d.ts +7 -0
  245. package/dist/server/oauth/validators.d.ts.map +1 -0
  246. package/dist/server/oauth/validators.js +51 -0
  247. package/dist/server/oauth/validators.js.map +1 -0
  248. package/dist/services/index.d.ts +3 -0
  249. package/dist/services/index.d.ts.map +1 -0
  250. package/dist/services/index.js +19 -0
  251. package/dist/services/index.js.map +1 -0
  252. package/dist/services/session-context.d.ts +57 -0
  253. package/dist/services/session-context.d.ts.map +1 -0
  254. package/dist/services/session-context.js +182 -0
  255. package/dist/services/session-context.js.map +1 -0
  256. package/dist/services/token-refresh-scheduler.d.ts +16 -0
  257. package/dist/services/token-refresh-scheduler.d.ts.map +1 -0
  258. package/dist/services/token-refresh-scheduler.js +66 -0
  259. package/dist/services/token-refresh-scheduler.js.map +1 -0
  260. package/dist/types/index.d.ts +2 -0
  261. package/dist/types/index.d.ts.map +1 -0
  262. package/dist/types/index.js +18 -0
  263. package/dist/types/index.js.map +1 -0
  264. package/dist/types/network.d.ts +7 -0
  265. package/dist/types/network.d.ts.map +1 -0
  266. package/dist/types/network.js +6 -0
  267. package/dist/types/network.js.map +1 -0
  268. package/dist/utils/context.d.ts +10 -0
  269. package/dist/utils/context.d.ts.map +1 -0
  270. package/dist/utils/context.js +44 -0
  271. package/dist/utils/context.js.map +1 -0
  272. package/dist/utils/env.d.ts +3 -0
  273. package/dist/utils/env.d.ts.map +1 -0
  274. package/dist/utils/env.js +16 -0
  275. package/dist/utils/env.js.map +1 -0
  276. package/dist/utils/index.d.ts +6 -0
  277. package/dist/utils/index.d.ts.map +1 -0
  278. package/dist/utils/index.js +22 -0
  279. package/dist/utils/index.js.map +1 -0
  280. package/dist/utils/mcp.d.ts +3 -0
  281. package/dist/utils/mcp.d.ts.map +1 -0
  282. package/dist/utils/mcp.js +7 -0
  283. package/dist/utils/mcp.js.map +1 -0
  284. package/dist/utils/network.d.ts +7 -0
  285. package/dist/utils/network.d.ts.map +1 -0
  286. package/dist/utils/network.js +63 -0
  287. package/dist/utils/network.js.map +1 -0
  288. package/dist/utils/pkce.d.ts +7 -0
  289. package/dist/utils/pkce.d.ts.map +1 -0
  290. package/dist/utils/pkce.js +43 -0
  291. package/dist/utils/pkce.js.map +1 -0
  292. package/dist/version.d.ts +3 -0
  293. package/dist/version.d.ts.map +1 -0
  294. package/dist/version.js +10 -0
  295. package/dist/version.js.map +1 -0
  296. package/docs/coding-style.md +30 -0
  297. package/ecosystem.config.json +17 -0
  298. package/eslint.config.cjs +95 -0
  299. package/package.json +54 -0
  300. package/src/cli.ts +158 -0
  301. package/src/config-builder.ts +76 -0
  302. package/src/consts.ts +3 -0
  303. package/src/creatio/auth/auth-manager.ts +27 -0
  304. package/src/creatio/auth/auth.ts +31 -0
  305. package/src/creatio/auth/index.ts +3 -0
  306. package/src/creatio/auth/providers/base-oauth2-provider.ts +62 -0
  307. package/src/creatio/auth/providers/base-provider.ts +42 -0
  308. package/src/creatio/auth/providers/index.ts +4 -0
  309. package/src/creatio/auth/providers/legacy-provider.ts +70 -0
  310. package/src/creatio/auth/providers/oauth2-code-provider.ts +252 -0
  311. package/src/creatio/auth/providers/oauth2-provider.ts +91 -0
  312. package/src/creatio/auth/providers/type.ts +5 -0
  313. package/src/creatio/client-config.ts +34 -0
  314. package/src/creatio/engines/crud/crud-engine.ts +47 -0
  315. package/src/creatio/engines/engine-manager.ts +102 -0
  316. package/src/creatio/engines/engine-registry.ts +36 -0
  317. package/src/creatio/engines/engine.ts +3 -0
  318. package/src/creatio/engines/index.ts +7 -0
  319. package/src/creatio/engines/process/process-engine.ts +20 -0
  320. package/src/creatio/engines/sys-settings/sys-settings-engine.ts +41 -0
  321. package/src/creatio/engines/user/user-engine.ts +20 -0
  322. package/src/creatio/index.ts +6 -0
  323. package/src/creatio/provider-context.ts +10 -0
  324. package/src/creatio/providers/crud-provider.ts +45 -0
  325. package/src/creatio/providers/index.ts +4 -0
  326. package/src/creatio/providers/process-provider.ts +15 -0
  327. package/src/creatio/providers/sys-settings-provider.ts +63 -0
  328. package/src/creatio/providers/user-provider.ts +12 -0
  329. package/src/creatio/services/creatio-service-context.ts +38 -0
  330. package/src/creatio/services/http-client.ts +174 -0
  331. package/src/creatio/services/index.ts +7 -0
  332. package/src/creatio/services/metadata-store.ts +181 -0
  333. package/src/creatio/services/odata-crud-provider.ts +210 -0
  334. package/src/creatio/services/process-service-provider.ts +76 -0
  335. package/src/creatio/services/sys-settings-service-provider.ts +192 -0
  336. package/src/creatio/services/user-info-provider.ts +41 -0
  337. package/src/index.ts +44 -0
  338. package/src/log.ts +141 -0
  339. package/src/server/http/creatio-oauth-handlers.ts +146 -0
  340. package/src/server/http/httpServer.ts +150 -0
  341. package/src/server/http/index.ts +5 -0
  342. package/src/server/http/mcp-handlers.ts +92 -0
  343. package/src/server/http/mcp-oauth-handlers.ts +108 -0
  344. package/src/server/http/middleware.ts +91 -0
  345. package/src/server/index.ts +2 -0
  346. package/src/server/mcp/filters.ts +97 -0
  347. package/src/server/mcp/index.ts +1 -0
  348. package/src/server/mcp/prompts-data.ts +896 -0
  349. package/src/server/mcp/server.ts +331 -0
  350. package/src/server/mcp/tools-data.ts +592 -0
  351. package/src/server/oauth/client-manager.ts +47 -0
  352. package/src/server/oauth/index.ts +6 -0
  353. package/src/server/oauth/oauth-server.ts +185 -0
  354. package/src/server/oauth/storage.ts +106 -0
  355. package/src/server/oauth/token-manager.ts +80 -0
  356. package/src/server/oauth/types.ts +55 -0
  357. package/src/server/oauth/validators.ts +56 -0
  358. package/src/services/index.ts +2 -0
  359. package/src/services/session-context.ts +232 -0
  360. package/src/services/token-refresh-scheduler.ts +68 -0
  361. package/src/types/index.ts +1 -0
  362. package/src/types/network.ts +7 -0
  363. package/src/utils/context.ts +49 -0
  364. package/src/utils/env.ts +12 -0
  365. package/src/utils/index.ts +5 -0
  366. package/src/utils/mcp.ts +8 -0
  367. package/src/utils/network.ts +65 -0
  368. package/src/utils/pkce.ts +39 -0
  369. package/src/version.ts +15 -0
  370. package/tsconfig.json +28 -0
@@ -0,0 +1,146 @@
1
+ import log from '../../log';
2
+ import { SessionContext } from '../../services';
3
+ import { runWithContext } from '../../utils';
4
+
5
+ import type { Server } from '../mcp';
6
+ import type { OAuthServer } from '../oauth';
7
+ import type { Request, Response } from 'express';
8
+
9
+ export class CreatioOAuthHandlers {
10
+ private readonly _sessionContext = SessionContext.instance;
11
+ private readonly _server: Server;
12
+ private readonly _oauthServer: OAuthServer;
13
+
14
+ constructor(server: Server, oauthServer: OAuthServer) {
15
+ this._server = server;
16
+ this._oauthServer = oauthServer;
17
+ }
18
+
19
+ private _mapAllSessionsToUser(userKey: string): void {
20
+ const sessions = this._sessionContext.getAllSessions();
21
+ const sessionIds = sessions.map((s) => s.id);
22
+ log.info('mapping_all_sessions', { userKey, sessionCount: sessionIds.length, sessionIds });
23
+ for (const sessionId of sessionIds) {
24
+ this._sessionContext.setSessionUserKey(sessionId, userKey);
25
+ }
26
+ }
27
+
28
+ public async handleOAuthStart(req: Request, res: Response): Promise<void> {
29
+ try {
30
+ const userKey = req.query.userKey as string;
31
+ const authKey = req.query.authKey as string;
32
+ const effectiveUserKey = userKey || authKey;
33
+ if (!effectiveUserKey) {
34
+ res.status(400).send(
35
+ 'Missing userKey parameter. Add ?userKey=your_user_key to URL',
36
+ );
37
+ return;
38
+ }
39
+ const state = this._sessionContext.createOAuthState(effectiveUserKey);
40
+ const url = await this._server.authProvider.getAuthorizeUrl(state);
41
+ const mcpParams = req.query as any;
42
+ if (mcpParams.client_id && mcpParams.redirect_uri) {
43
+ const urlObj = new URL(url);
44
+ const stateWithMcp = `${state}&client_id=${mcpParams.client_id}&redirect_uri=${encodeURIComponent(mcpParams.redirect_uri)}&code_challenge=${mcpParams.code_challenge}&code_challenge_method=${mcpParams.code_challenge_method}&mcp_state=${mcpParams.state || ''}`;
45
+ urlObj.searchParams.set('state', stateWithMcp);
46
+ return res.redirect(302, urlObj.toString());
47
+ }
48
+ res.redirect(302, url);
49
+ } catch (err: any) {
50
+ log.error('oauth.start.error', { error: String(err?.message ?? err) });
51
+ res.status(500).send('OAuth start failed');
52
+ }
53
+ }
54
+
55
+ public async handleOAuthCallback(req: Request, res: Response): Promise<void> {
56
+ try {
57
+ const code = String(req.query?.code ?? '') || String((req as any).body?.code ?? '');
58
+ const state = String(req.query?.state ?? '') || String((req as any).body?.state ?? '');
59
+ log.info('oauth.callback.start', {
60
+ code: code ? '***' + code.slice(-4) : 'missing',
61
+ state: state ? state.substring(0, 50) + '...' : 'missing',
62
+ fullState: state,
63
+ });
64
+ if (!code || !state) {
65
+ res.status(400).send('Missing code or state');
66
+ return;
67
+ }
68
+ const stateParts = state.split('&');
69
+ const creatioState = stateParts[0];
70
+ log.info('oauth.callback.state_parse', {
71
+ originalState: state,
72
+ creatioState,
73
+ hasMcpParams: stateParts.length > 1,
74
+ });
75
+ if (!creatioState) {
76
+ log.error('oauth.callback.no_creatio_state', { originalState: state });
77
+ res.status(400).send('Invalid state format');
78
+ return;
79
+ }
80
+ const userKey = this._sessionContext.validateAndConsumeOAuthState(creatioState);
81
+ if (!userKey) {
82
+ log.error('oauth.callback.creatio_state_invalid', { creatioState });
83
+ res.status(400).send('Unknown or expired state');
84
+ return;
85
+ }
86
+ await runWithContext({ userKey }, async () =>
87
+ this._server.authProvider.finishAuthorization(code),
88
+ );
89
+ this._mapAllSessionsToUser(userKey);
90
+ const stateParams = new URLSearchParams(state);
91
+ const clientId = stateParams.get('client_id');
92
+ const redirectUri = stateParams.get('redirect_uri');
93
+ const codeChallenge = stateParams.get('code_challenge');
94
+ if (clientId && redirectUri && codeChallenge) {
95
+ const mcpState = stateParams.get('mcp_state');
96
+ log.info('oauth.callback.state_validation', {
97
+ mcpState,
98
+ clientId,
99
+ hasState: !!mcpState,
100
+ });
101
+ if (mcpState && !this._oauthServer.validateState(mcpState, clientId)) {
102
+ log.error('oauth.callback.state_invalid', { mcpState, clientId });
103
+ const errorUrl = new URL(redirectUri);
104
+ errorUrl.searchParams.set('error', 'invalid_request');
105
+ errorUrl.searchParams.set('error_description', 'Unknown or expired state');
106
+ if (mcpState) {
107
+ errorUrl.searchParams.set('state', mcpState);
108
+ }
109
+ return res.redirect(errorUrl.toString());
110
+ }
111
+ const authCode = this._oauthServer.generateAuthorizationCode(
112
+ clientId,
113
+ redirectUri,
114
+ codeChallenge,
115
+ stateParams.get('code_challenge_method') || 'S256',
116
+ userKey,
117
+ );
118
+ const redirectUrl = new URL(redirectUri);
119
+ redirectUrl.searchParams.set('code', authCode);
120
+ if (mcpState) {
121
+ redirectUrl.searchParams.set('state', mcpState);
122
+ }
123
+ return res.redirect(redirectUrl.toString());
124
+ }
125
+ res.status(200).send('Authorization successful. You can close this window.');
126
+ } catch (err: any) {
127
+ log.error('oauth.callback.error', { error: String(err?.message ?? err) });
128
+ res.status(500).send('OAuth callback failed');
129
+ }
130
+ }
131
+
132
+ public async handleOAuthRevoke(req: Request, res: Response): Promise<void> {
133
+ try {
134
+ const userKey = (req.query.userKey as string) || (req.body?.userKey as string);
135
+ if (!userKey) {
136
+ res.status(400).send('Missing userKey parameter');
137
+ return;
138
+ }
139
+ await runWithContext({ userKey }, async () => this._server.authProvider.revoke());
140
+ res.status(200).send('Revoked');
141
+ } catch (err: any) {
142
+ log.error('oauth.revoke.error', { error: String(err?.message ?? err) });
143
+ res.status(500).send('OAuth revoke failed');
144
+ }
145
+ }
146
+ }
@@ -0,0 +1,150 @@
1
+ import * as http from 'http';
2
+ import { Socket } from 'node:net';
3
+
4
+ import express from 'express';
5
+
6
+ import { AuthProviderType } from '../../creatio/';
7
+ import log from '../../log';
8
+ import { SessionContext } from '../../services';
9
+ import { OAuthServer } from '../oauth';
10
+
11
+ import { CreatioOAuthHandlers } from './creatio-oauth-handlers';
12
+ import { McpHandlers } from './mcp-handlers';
13
+ import { MCPOAuthHandlers } from './mcp-oauth-handlers';
14
+ import { HttpMiddleware } from './middleware';
15
+
16
+ import type { Server } from '../mcp';
17
+
18
+ export class HttpServer {
19
+ private readonly _server: Server;
20
+ private readonly _app = express();
21
+ private readonly _connections = new Set<Socket>();
22
+ private _srv!: http.Server;
23
+ private readonly _sessionContext = SessionContext.instance;
24
+ private readonly _oauthServer: OAuthServer;
25
+ private readonly _middleware: HttpMiddleware;
26
+ private readonly _mcpHandlers: McpHandlers;
27
+ private readonly _creatioOauthHandlers: CreatioOAuthHandlers;
28
+ private readonly _mcpOauthHandlers: MCPOAuthHandlers;
29
+
30
+ constructor(server: Server) {
31
+ this._server = server;
32
+ this._oauthServer = new OAuthServer();
33
+ this._middleware = new HttpMiddleware(this._oauthServer);
34
+ this._mcpHandlers = new McpHandlers(this._server);
35
+ this._creatioOauthHandlers = new CreatioOAuthHandlers(this._server, this._oauthServer);
36
+ this._mcpOauthHandlers = new MCPOAuthHandlers(this._oauthServer);
37
+ this._setupMiddleware();
38
+ this._setupRoutes();
39
+ }
40
+
41
+ private _setupMiddleware(): void {
42
+ this._app.use(this._middleware.correlationId());
43
+ this._app.use(this._middleware.requestLogging());
44
+ this._app.use(express.json());
45
+ this._app.use(express.urlencoded({ extended: true }));
46
+ if (this._isNeedMCPOAuth()) {
47
+ this._app.use('/mcp', this._middleware.bearerAuth());
48
+ }
49
+ this._app.use(this._middleware.errorHandler());
50
+ }
51
+
52
+ private _setupRoutes(): void {
53
+ this._setupMCPEndpoints();
54
+ if (this._isNeedMCPOAuth()) {
55
+ this._setupCreatioOAuthEndpoints();
56
+ this._setupMCPOAuthEndpoints();
57
+ }
58
+ }
59
+
60
+ private _setupMCPEndpoints(): void {
61
+ this._app.post('/mcp', (req, res) => this._mcpHandlers.handleMcpPost(req, res));
62
+ this._app.get('/mcp', (req, res) => this._mcpHandlers.handleSessionRequest(req, res));
63
+ this._app.delete('/mcp', (req, res) => this._mcpHandlers.handleSessionRequest(req, res));
64
+ }
65
+
66
+ private _isNeedMCPOAuth(): boolean {
67
+ return this._server.authProvider.type === AuthProviderType.OAuth2Code;
68
+ }
69
+
70
+ private _setupCreatioOAuthEndpoints(): void {
71
+ this._app.get('/oauth/start', (req, res) =>
72
+ this._creatioOauthHandlers.handleOAuthStart(req, res),
73
+ );
74
+ this._app.get('/oauth/callback', (req, res) =>
75
+ this._creatioOauthHandlers.handleOAuthCallback(req, res),
76
+ );
77
+ this._app.post('/oauth/revoke', (req, res) =>
78
+ this._creatioOauthHandlers.handleOAuthRevoke(req, res),
79
+ );
80
+ }
81
+
82
+ private _setupMCPOAuthEndpoints(): void {
83
+ this._app.get('/.well-known/oauth-authorization-server', (req, res) =>
84
+ this._mcpOauthHandlers.handleMetadata(req, res),
85
+ );
86
+ this._app.post('/register', (req, res) =>
87
+ this._mcpOauthHandlers.handleClientRegistration(req, res),
88
+ );
89
+ this._app.get('/authorize', (req, res) =>
90
+ this._mcpOauthHandlers.handleAuthorization(req, res),
91
+ );
92
+ this._app.post('/token', (req, res) =>
93
+ this._mcpOauthHandlers.handleTokenExchange(req, res),
94
+ );
95
+ }
96
+
97
+ public start(port: number) {
98
+ return new Promise<void>((resolve, reject) => {
99
+ this._srv = this._app.listen(port, () => {
100
+ log.httpStart(port);
101
+ resolve();
102
+ });
103
+ this._srv.keepAliveTimeout = 5000;
104
+ this._srv.headersTimeout = Math.max(this._srv.keepAliveTimeout + 1000, 6000);
105
+ this._srv.on('error', (err) => {
106
+ log.error('http.start.error', { error: String(err), port });
107
+ reject(err);
108
+ });
109
+ this._srv.on('connection', (socket: Socket) => {
110
+ this._connections.add(socket);
111
+ socket.once('close', () => this._connections.delete(socket));
112
+ });
113
+ });
114
+ }
115
+
116
+ public async stop() {
117
+ try {
118
+ if (this._server.authProvider && 'cancelAllRefresh' in this._server.authProvider) {
119
+ (this._server.authProvider as any).cancelAllRefresh();
120
+ }
121
+ } catch (err) {
122
+ log.warn('token_refresh_cleanup_failed', { error: String(err) });
123
+ }
124
+ if (this._srv) {
125
+ try {
126
+ await this._server.stopMcp();
127
+ await new Promise<void>((resolve) => {
128
+ this._srv.close(() => resolve());
129
+ });
130
+ } catch (err) {
131
+ log.error('http.stop.error', { error: String(err) });
132
+ }
133
+ }
134
+ for (const socket of Array.from(this._connections)) {
135
+ try {
136
+ socket.destroy();
137
+ } catch {}
138
+ }
139
+ this._connections.clear();
140
+ const sessions = this._sessionContext.getAllSessions();
141
+ for (const session of sessions) {
142
+ try {
143
+ session.transport?.close();
144
+ } catch (err) {
145
+ log.warn('transport.close.failed', { sessionId: session.id, error: String(err) });
146
+ }
147
+ this._sessionContext.deleteSession(session.id);
148
+ }
149
+ }
150
+ }
@@ -0,0 +1,5 @@
1
+ export * from './httpServer';
2
+ export * from './mcp-handlers';
3
+ export * from './middleware';
4
+ export * from './creatio-oauth-handlers';
5
+ export * from './mcp-oauth-handlers';
@@ -0,0 +1,92 @@
1
+ import { randomUUID } from 'node:crypto';
2
+
3
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
+ import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
5
+
6
+ import log from '../../log';
7
+ import { SessionContext } from '../../services';
8
+ import {
9
+ getClientIp,
10
+ getSessionIdFromRequest,
11
+ getUserKeyFromRequest,
12
+ runWithContext,
13
+ } from '../../utils';
14
+
15
+ import type { Server } from '../mcp';
16
+ import type { Request, Response } from 'express';
17
+
18
+ export class McpHandlers {
19
+ private readonly _sessionContext = SessionContext.instance;
20
+ private readonly _server: Server;
21
+
22
+ constructor(server: Server) {
23
+ this._server = server;
24
+ }
25
+
26
+ public async handleMcpPost(req: Request, res: Response): Promise<void> {
27
+ const sessionId = getSessionIdFromRequest(req);
28
+ const bearerUserKey = (req as any).userKey;
29
+ let transport: StreamableHTTPServerTransport | undefined;
30
+ const remoteIp = getClientIp(req);
31
+ if (sessionId && this._sessionContext.hasSession(sessionId)) {
32
+ const session = this._sessionContext.getSession(sessionId);
33
+ transport = session?.transport;
34
+ if (session && !session.isLogged) {
35
+ this._sessionContext.markSessionAsLogged(sessionId);
36
+ log.sessionConnect(sessionId, String(remoteIp));
37
+ }
38
+ } else if (!sessionId && isInitializeRequest(req.body)) {
39
+ transport = new StreamableHTTPServerTransport({
40
+ sessionIdGenerator: () => randomUUID(),
41
+ onsessioninitialized: (sid) => {
42
+ if (transport) {
43
+ const session = this._sessionContext.createSession(
44
+ sid,
45
+ bearerUserKey,
46
+ remoteIp,
47
+ );
48
+ this._sessionContext.setSessionTransport(sid, transport);
49
+ this._sessionContext.markSessionAsLogged(sid);
50
+ log.sessionConnect(sid, String(remoteIp));
51
+ }
52
+ },
53
+ });
54
+ transport.onclose = () => {
55
+ if (transport?.sessionId) {
56
+ log.sessionDisconnect(transport.sessionId, String(remoteIp));
57
+ this._sessionContext.deleteSession(transport.sessionId);
58
+ }
59
+ };
60
+ const mcp = await this._server.startMcp();
61
+ await mcp.connect(transport as any);
62
+ } else {
63
+ res.status(400).json({
64
+ jsonrpc: '2.0',
65
+ error: { code: -32000, message: 'Bad Request: No valid session ID provided' },
66
+ id: null,
67
+ });
68
+ return;
69
+ }
70
+ const session = this._sessionContext.getSession(sessionId);
71
+ const userKey = bearerUserKey || session?.userKey;
72
+ await runWithContext({ userKey, sessionId }, async () =>
73
+ transport!.handleRequest(req, res, req.body),
74
+ );
75
+ }
76
+
77
+ public async handleSessionRequest(req: Request, res: Response): Promise<void> {
78
+ const sessionId = req.headers['mcp-session-id'] as string | undefined;
79
+ if (!sessionId || !this._sessionContext.hasSession(sessionId)) {
80
+ res.status(400).send('Invalid or missing session ID');
81
+ return;
82
+ }
83
+ const session = this._sessionContext.getSession(sessionId);
84
+ const transport = session?.transport;
85
+ if (!transport) {
86
+ res.status(400).send('Session has no transport');
87
+ return;
88
+ }
89
+ const userKey = getUserKeyFromRequest(req as any);
90
+ await runWithContext({ userKey, sessionId }, async () => transport.handleRequest(req, res));
91
+ }
92
+ }
@@ -0,0 +1,108 @@
1
+ import { randomUUID } from 'node:crypto';
2
+
3
+ import log from '../../log';
4
+ import { OAuthValidators } from '../oauth/validators';
5
+
6
+ import type { OAuthServer } from '../oauth';
7
+ import type { Request, Response } from 'express';
8
+
9
+ export class MCPOAuthHandlers {
10
+ private readonly _oauthServer: OAuthServer;
11
+
12
+ constructor(oauthServer: OAuthServer) {
13
+ this._oauthServer = oauthServer;
14
+ }
15
+
16
+ public handleMetadata(req: Request, res: Response): void {
17
+ const metadata = this._oauthServer.getAuthorizationServerMetadata();
18
+ res.json(metadata);
19
+ }
20
+
21
+ public handleClientRegistration(req: Request, res: Response): Response | void {
22
+ try {
23
+ const { redirect_uris } = req.body;
24
+ const validationError = OAuthValidators.validateClientRegistration(redirect_uris);
25
+ if (validationError) {
26
+ return res.status(400).json({
27
+ error: 'invalid_request',
28
+ error_description: validationError,
29
+ });
30
+ }
31
+ const client = this._oauthServer.registerClient(redirect_uris);
32
+ res.status(201).json(client);
33
+ } catch (error) {
34
+ log.error('oauth.register.error', { error: String(error) });
35
+ res.status(500).json({
36
+ error: 'server_error',
37
+ error_description: 'Failed to register client',
38
+ });
39
+ }
40
+ }
41
+
42
+ public async handleAuthorization(req: Request, res: Response): Promise<void> {
43
+ try {
44
+ const params = {
45
+ client_id: req.query.client_id as string,
46
+ redirect_uri: req.query.redirect_uri as string,
47
+ response_type: req.query.response_type as string,
48
+ state: req.query.state as string,
49
+ code_challenge: req.query.code_challenge as string,
50
+ code_challenge_method: req.query.code_challenge_method as string,
51
+ scope: req.query.scope as string,
52
+ };
53
+ const validationError = this._oauthServer.validateAuthorizationRequest(params);
54
+ if (validationError) {
55
+ const errorUrl = new URL(params.redirect_uri);
56
+ errorUrl.searchParams.set('error', validationError.error);
57
+ if (validationError.error_description) {
58
+ errorUrl.searchParams.set(
59
+ 'error_description',
60
+ validationError.error_description,
61
+ );
62
+ }
63
+ if (params.state) {
64
+ errorUrl.searchParams.set('state', params.state);
65
+ }
66
+ return res.redirect(errorUrl.toString());
67
+ }
68
+ if (params.state) {
69
+ this._oauthServer.storeState(params.state, params.client_id);
70
+ }
71
+ const authKey = randomUUID();
72
+ const creatioAuthUrl = `/oauth/start?authKey=${authKey}&client_id=${params.client_id}&redirect_uri=${encodeURIComponent(params.redirect_uri)}&code_challenge=${params.code_challenge}&code_challenge_method=${params.code_challenge_method}&state=${params.state || ''}`;
73
+ res.redirect(creatioAuthUrl);
74
+ } catch (error) {
75
+ log.error('oauth.authorize.error', { error: String(error) });
76
+ res.status(500).send('Authorization failed');
77
+ }
78
+ }
79
+
80
+ public async handleTokenExchange(req: Request, res: Response): Promise<Response | void> {
81
+ try {
82
+ const tokenParams = req.body || {};
83
+ log.info('oauth.token.request', {
84
+ contentType: req.headers['content-type'],
85
+ hasBody: !!req.body,
86
+ bodyKeys: req.body ? Object.keys(req.body) : [],
87
+ params: {
88
+ grant_type: tokenParams.grant_type,
89
+ code: tokenParams.code ? '***' + tokenParams.code.slice(-4) : 'missing',
90
+ client_id: tokenParams.client_id,
91
+ redirect_uri: tokenParams.redirect_uri,
92
+ has_code_verifier: !!tokenParams.code_verifier,
93
+ },
94
+ });
95
+ const result = await this._oauthServer.exchangeCodeForToken(tokenParams);
96
+ if ('error' in result) {
97
+ return res.status(400).json(result);
98
+ }
99
+ res.json(result);
100
+ } catch (error) {
101
+ log.error('oauth.token.error', { error: String(error) });
102
+ res.status(500).json({
103
+ error: 'server_error',
104
+ error_description: 'Failed to exchange token',
105
+ });
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,91 @@
1
+ import { randomUUID } from 'crypto';
2
+
3
+ import log from '../../log';
4
+ import { getClientIp } from '../../utils';
5
+
6
+ import type { OAuthServer } from '../oauth';
7
+ import type { NextFunction, Request, Response } from 'express';
8
+
9
+ export class HttpMiddleware {
10
+ private readonly _oauthServer: OAuthServer;
11
+
12
+ constructor(oauthServer: OAuthServer) {
13
+ this._oauthServer = oauthServer;
14
+ }
15
+
16
+ public bearerAuth() {
17
+ return (req: Request, res: Response, next: NextFunction) => {
18
+ const authHeader = req.headers.authorization;
19
+ if (authHeader && authHeader.startsWith('Bearer ')) {
20
+ const token = authHeader.slice(7);
21
+ const userKey = this._oauthServer.validateAccessToken(token);
22
+ if (userKey) {
23
+ (req as any).userKey = userKey;
24
+ return next();
25
+ }
26
+ }
27
+ res.status(401).json({
28
+ error: 'unauthorized',
29
+ error_description:
30
+ 'Valid Bearer token required. Use OAuth 2.1 flow to obtain access token.',
31
+ });
32
+ };
33
+ }
34
+
35
+ public errorHandler() {
36
+ return (error: Error, req: Request, res: Response, next: NextFunction) => {
37
+ log.error('http.error', {
38
+ error: error.message,
39
+ stack: error.stack,
40
+ path: req.path,
41
+ method: req.method,
42
+ });
43
+ if (res.headersSent) {
44
+ return next(error);
45
+ }
46
+ res.status(500).json({
47
+ error: 'server_error',
48
+ error_description: 'Internal server error',
49
+ });
50
+ };
51
+ }
52
+
53
+ public correlationId() {
54
+ return (req: Request, res: Response, next: NextFunction) => {
55
+ const correlationId = (req.headers['x-correlation-id'] as string) || randomUUID();
56
+ log.setCorrelationId(correlationId);
57
+ (req as any).correlationId = correlationId;
58
+ res.setHeader('X-Correlation-ID', correlationId);
59
+ res.on('finish', () => {
60
+ log.clearCorrelationId();
61
+ });
62
+ next();
63
+ };
64
+ }
65
+
66
+ public requestLogging() {
67
+ return (req: Request, res: Response, next: NextFunction) => {
68
+ const startTime = Date.now();
69
+ const ip = getClientIp(req);
70
+ const userAgent = req.headers['user-agent'];
71
+ const correlationId = (req as any).correlationId;
72
+ log.httpRequest(req.method, req.url, {
73
+ ip,
74
+ userAgent,
75
+ correlationId,
76
+ contentLength: req.headers['content-length'],
77
+ contentType: req.headers['content-type'],
78
+ });
79
+ res.on('finish', () => {
80
+ const duration = Date.now() - startTime;
81
+ log.httpResponse(req.method, req.url, res.statusCode, duration, {
82
+ ip,
83
+ correlationId,
84
+ contentLength: res.getHeader('content-length'),
85
+ contentType: res.getHeader('content-type'),
86
+ });
87
+ });
88
+ next();
89
+ };
90
+ }
91
+ }
@@ -0,0 +1,2 @@
1
+ export * from './http';
2
+ export * from './mcp';
@@ -0,0 +1,97 @@
1
+ function isGuid(s: unknown): s is string {
2
+ return (
3
+ typeof s === 'string' &&
4
+ /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(s)
5
+ );
6
+ }
7
+
8
+ function isIdish(field: string): boolean {
9
+ return /(^|\/)Id$/.test(field) || /Id$/i.test(field);
10
+ }
11
+
12
+ function escapeStr(val: string): string {
13
+ return val.replace(/'/g, "''");
14
+ }
15
+
16
+ function literalFor(field: string, value: any): string {
17
+ if (value == null) {
18
+ return 'null';
19
+ }
20
+ const t = typeof value;
21
+ if (t === 'number') {
22
+ return String(value);
23
+ }
24
+ if (t === 'boolean') {
25
+ return value ? 'true' : 'false';
26
+ }
27
+ if (t === 'string') {
28
+ const v = String(value);
29
+ const isNavigationProperty = field.includes('/');
30
+ if (isGuid(v) && isIdish(field) && !isNavigationProperty) {
31
+ return v;
32
+ }
33
+ return `'${escapeStr(v)}'`;
34
+ }
35
+ return `'${escapeStr(JSON.stringify(value))}'`;
36
+ }
37
+
38
+ function buildCondition(c: any): string | undefined {
39
+ if (!c || !c.field) {
40
+ return undefined;
41
+ }
42
+ const field = String(c.field);
43
+ if (Array.isArray((c as any).in)) {
44
+ const values = (c as any).in as any[];
45
+ if (!values.length) {
46
+ return undefined;
47
+ }
48
+ const parts = values.map((v) => `${field} eq ${literalFor(field, v)}`);
49
+ return parts.length === 1 ? parts[0] : `(${parts.join(' or ')})`;
50
+ }
51
+ const op = String(c.op || 'eq');
52
+ const value = (c as any).value;
53
+ if (op === 'contains' || op === 'startswith' || op === 'endswith') {
54
+ return `${op}(${field},${literalFor(field, value)})`;
55
+ }
56
+ if (value == null && (op === 'eq' || op === 'ne')) {
57
+ return `${field} ${op} null`;
58
+ }
59
+ return `${field} ${op} ${literalFor(field, value)}`;
60
+ }
61
+
62
+ export function buildFilterFromStructured(filters: any | undefined): string | undefined {
63
+ if (!filters || typeof filters !== 'object') {
64
+ return undefined;
65
+ }
66
+ const andParts: string[] = [];
67
+ const orParts: string[] = [];
68
+ if (Array.isArray(filters.all)) {
69
+ for (const c of filters.all) {
70
+ const s = buildCondition(c);
71
+ if (s) {
72
+ andParts.push(s);
73
+ }
74
+ }
75
+ }
76
+ if (Array.isArray(filters.any)) {
77
+ for (const c of filters.any) {
78
+ const s = buildCondition(c);
79
+ if (s) {
80
+ orParts.push(s);
81
+ }
82
+ }
83
+ }
84
+ const andStr = andParts.join(' and ');
85
+ const orStr = orParts.join(' or ');
86
+ const parts: string[] = [];
87
+ if (andStr) {
88
+ parts.push(andParts.length > 1 ? `(${andStr})` : andStr);
89
+ }
90
+ if (orStr) {
91
+ parts.push(orParts.length > 1 ? `(${orStr})` : orStr);
92
+ }
93
+ if (!parts.length) {
94
+ return undefined;
95
+ }
96
+ return parts.join(' and ');
97
+ }
@@ -0,0 +1 @@
1
+ export * from './server';