@pikku/core 0.11.1 → 0.12.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 (363) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/crypto-utils.d.ts +2 -0
  3. package/dist/crypto-utils.js +78 -0
  4. package/dist/errors/error-handler.js +3 -3
  5. package/dist/errors/errors.d.ts +8 -0
  6. package/dist/errors/errors.js +16 -0
  7. package/dist/errors/index.d.ts +0 -1
  8. package/dist/errors/index.js +0 -1
  9. package/dist/function/function-runner.d.ts +10 -3
  10. package/dist/function/function-runner.js +136 -31
  11. package/dist/function/functions.types.d.ts +35 -12
  12. package/dist/function/functions.types.js +16 -6
  13. package/dist/function/index.d.ts +2 -2
  14. package/dist/function/index.js +1 -2
  15. package/dist/handle-error.js +1 -10
  16. package/dist/index.d.ts +30 -24
  17. package/dist/index.js +19 -27
  18. package/dist/middleware/auth-apikey.d.ts +1 -1
  19. package/dist/middleware/auth-apikey.js +3 -3
  20. package/dist/middleware/auth-bearer.d.ts +1 -1
  21. package/dist/middleware/auth-bearer.js +3 -6
  22. package/dist/middleware/auth-cookie.d.ts +1 -1
  23. package/dist/middleware/auth-cookie.js +6 -8
  24. package/dist/middleware/cors.d.ts +46 -0
  25. package/dist/middleware/cors.js +73 -0
  26. package/dist/middleware/index.d.ts +5 -3
  27. package/dist/middleware/index.js +5 -3
  28. package/dist/middleware/remote-auth.d.ts +5 -0
  29. package/dist/middleware/remote-auth.js +55 -0
  30. package/dist/middleware/timeout.d.ts +1 -1
  31. package/dist/middleware-runner.d.ts +3 -14
  32. package/dist/middleware-runner.js +14 -16
  33. package/dist/permissions.d.ts +3 -86
  34. package/dist/permissions.js +20 -80
  35. package/dist/pikku-state.d.ts +33 -104
  36. package/dist/pikku-state.js +150 -66
  37. package/dist/schema.d.ts +8 -6
  38. package/dist/schema.js +31 -18
  39. package/dist/services/ai-agent-runner-service.d.ts +24 -0
  40. package/dist/services/ai-agent-runner-service.js +1 -0
  41. package/dist/services/ai-run-state-service.d.ts +13 -0
  42. package/dist/services/ai-run-state-service.js +1 -0
  43. package/dist/services/ai-storage-service.d.ts +18 -0
  44. package/dist/services/ai-storage-service.js +1 -0
  45. package/dist/services/deployment-service.d.ts +19 -0
  46. package/dist/services/deployment-service.js +1 -0
  47. package/dist/services/gopass-secrets.d.ts +47 -0
  48. package/dist/services/gopass-secrets.js +94 -0
  49. package/dist/services/in-memory-trigger-service.d.ts +23 -0
  50. package/dist/services/in-memory-trigger-service.js +50 -0
  51. package/dist/services/in-memory-workflow-service.d.ts +59 -0
  52. package/dist/services/in-memory-workflow-service.js +287 -0
  53. package/dist/services/index.d.ts +25 -11
  54. package/dist/services/index.js +10 -13
  55. package/dist/services/local-secrets.d.ts +23 -0
  56. package/dist/services/local-secrets.js +45 -0
  57. package/dist/services/local-variables.d.ts +5 -0
  58. package/dist/services/local-variables.js +18 -0
  59. package/dist/services/scheduler-service.d.ts +21 -1
  60. package/dist/services/scheduler-service.js +14 -0
  61. package/dist/services/schema-service.d.ts +6 -0
  62. package/dist/services/scoped-secret-service.d.ts +16 -0
  63. package/dist/services/scoped-secret-service.js +35 -0
  64. package/dist/services/secret-service.d.ts +25 -4
  65. package/dist/services/trigger-service.d.ts +23 -0
  66. package/dist/services/trigger-service.js +1 -0
  67. package/dist/services/typed-secret-service.d.ts +30 -0
  68. package/dist/services/typed-secret-service.js +40 -0
  69. package/dist/services/typed-variables-service.d.ts +27 -0
  70. package/dist/services/typed-variables-service.js +46 -0
  71. package/dist/services/user-session-service.d.ts +13 -0
  72. package/dist/services/user-session-service.js +17 -0
  73. package/dist/services/variables-service.d.ts +5 -0
  74. package/dist/services/workflow-service.d.ts +43 -0
  75. package/dist/services/workflow-service.js +1 -0
  76. package/dist/types/core.types.d.ts +54 -10
  77. package/dist/types/core.types.js +7 -0
  78. package/dist/types/state.types.d.ts +127 -0
  79. package/dist/types/state.types.js +1 -0
  80. package/dist/utils.d.ts +10 -1
  81. package/dist/utils.js +60 -3
  82. package/dist/version.d.ts +6 -0
  83. package/dist/version.js +19 -0
  84. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +29 -0
  85. package/dist/wirings/ai-agent/ai-agent-memory.js +199 -0
  86. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +9 -0
  87. package/dist/wirings/ai-agent/ai-agent-model-config.js +36 -0
  88. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +60 -0
  89. package/dist/wirings/ai-agent/ai-agent-prepare.js +312 -0
  90. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +15 -0
  91. package/dist/wirings/ai-agent/ai-agent-registry.js +47 -0
  92. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +3 -0
  93. package/dist/wirings/ai-agent/ai-agent-runner.js +96 -0
  94. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +11 -0
  95. package/dist/wirings/ai-agent/ai-agent-stream.js +503 -0
  96. package/dist/wirings/ai-agent/ai-agent.types.d.ts +254 -0
  97. package/dist/wirings/ai-agent/ai-agent.types.js +1 -0
  98. package/dist/wirings/ai-agent/index.d.ts +5 -0
  99. package/dist/wirings/ai-agent/index.js +4 -0
  100. package/dist/wirings/channel/channel-common.d.ts +7 -4
  101. package/dist/wirings/channel/channel-common.js +15 -8
  102. package/dist/wirings/channel/channel-handler.js +13 -4
  103. package/dist/wirings/channel/channel-middleware-runner.d.ts +9 -0
  104. package/dist/wirings/channel/channel-middleware-runner.js +73 -0
  105. package/dist/wirings/channel/channel-runner.js +12 -12
  106. package/dist/wirings/channel/channel.types.d.ts +5 -1
  107. package/dist/wirings/channel/define-channel-routes.d.ts +21 -0
  108. package/dist/wirings/channel/define-channel-routes.js +23 -0
  109. package/dist/wirings/channel/index.d.ts +10 -8
  110. package/dist/wirings/channel/index.js +7 -8
  111. package/dist/wirings/channel/local/index.d.ts +3 -3
  112. package/dist/wirings/channel/local/index.js +3 -3
  113. package/dist/wirings/channel/local/local-channel-runner.js +18 -6
  114. package/dist/wirings/channel/log-channels.js +1 -1
  115. package/dist/wirings/channel/serverless/index.d.ts +1 -1
  116. package/dist/wirings/channel/serverless/index.js +1 -1
  117. package/dist/wirings/channel/serverless/serverless-channel-runner.js +17 -6
  118. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
  119. package/dist/wirings/cli/channel/index.d.ts +1 -1
  120. package/dist/wirings/cli/channel/index.js +1 -1
  121. package/dist/wirings/cli/cli-runner.d.ts +1 -1
  122. package/dist/wirings/cli/cli-runner.js +22 -18
  123. package/dist/wirings/cli/cli.types.d.ts +7 -6
  124. package/dist/wirings/cli/define-cli-commands.d.ts +19 -0
  125. package/dist/wirings/cli/define-cli-commands.js +20 -0
  126. package/dist/wirings/cli/index.d.ts +2 -3
  127. package/dist/wirings/cli/index.js +1 -3
  128. package/dist/wirings/http/http-routes.d.ts +69 -0
  129. package/dist/wirings/http/http-routes.js +139 -0
  130. package/dist/wirings/http/http-runner.d.ts +2 -2
  131. package/dist/wirings/http/http-runner.js +62 -27
  132. package/dist/wirings/http/http.types.d.ts +77 -24
  133. package/dist/wirings/http/index.d.ts +5 -4
  134. package/dist/wirings/http/index.js +4 -3
  135. package/dist/wirings/http/log-http-routes.js +1 -1
  136. package/dist/wirings/http/routers/path-to-regex.js +2 -2
  137. package/dist/wirings/mcp/index.d.ts +4 -3
  138. package/dist/wirings/mcp/index.js +3 -3
  139. package/dist/wirings/mcp/mcp-runner.d.ts +1 -3
  140. package/dist/wirings/mcp/mcp-runner.js +42 -56
  141. package/dist/wirings/mcp/mcp.types.d.ts +3 -3
  142. package/dist/wirings/node/index.d.ts +2 -0
  143. package/dist/wirings/node/index.js +1 -0
  144. package/dist/wirings/node/node.types.d.ts +20 -0
  145. package/dist/wirings/node/node.types.js +1 -0
  146. package/dist/wirings/oauth2/index.d.ts +3 -0
  147. package/dist/wirings/oauth2/index.js +2 -0
  148. package/dist/wirings/oauth2/oauth2-client.d.ts +47 -0
  149. package/dist/wirings/oauth2/oauth2-client.js +267 -0
  150. package/dist/wirings/oauth2/oauth2.types.d.ts +65 -0
  151. package/dist/wirings/oauth2/oauth2.types.js +4 -0
  152. package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +20 -0
  153. package/dist/wirings/oauth2/wire-oauth2-credential.js +21 -0
  154. package/dist/wirings/queue/index.d.ts +2 -2
  155. package/dist/wirings/queue/index.js +1 -1
  156. package/dist/wirings/queue/queue-runner.d.ts +7 -0
  157. package/dist/wirings/queue/queue-runner.js +23 -12
  158. package/dist/wirings/queue/queue.types.d.ts +8 -2
  159. package/dist/wirings/rpc/index.d.ts +1 -1
  160. package/dist/wirings/rpc/index.js +1 -1
  161. package/dist/wirings/rpc/rpc-runner.d.ts +40 -13
  162. package/dist/wirings/rpc/rpc-runner.js +191 -25
  163. package/dist/wirings/rpc/rpc-types.d.ts +15 -4
  164. package/dist/wirings/scheduler/index.d.ts +3 -3
  165. package/dist/wirings/scheduler/index.js +2 -3
  166. package/dist/wirings/scheduler/log-schedulers.js +1 -1
  167. package/dist/wirings/scheduler/scheduler-runner.d.ts +5 -0
  168. package/dist/wirings/scheduler/scheduler-runner.js +28 -10
  169. package/dist/wirings/secret/index.d.ts +3 -0
  170. package/dist/wirings/secret/index.js +2 -0
  171. package/dist/wirings/secret/secret.types.d.ts +27 -0
  172. package/dist/wirings/secret/secret.types.js +1 -0
  173. package/dist/wirings/secret/validate-secret-definitions.d.ts +6 -0
  174. package/dist/wirings/secret/validate-secret-definitions.js +55 -0
  175. package/dist/wirings/trigger/index.d.ts +3 -0
  176. package/dist/wirings/trigger/index.js +2 -0
  177. package/dist/wirings/trigger/pikku-trigger-service.d.ts +26 -0
  178. package/dist/wirings/trigger/pikku-trigger-service.js +75 -0
  179. package/dist/wirings/trigger/trigger-runner.d.ts +42 -0
  180. package/dist/wirings/trigger/trigger-runner.js +85 -0
  181. package/dist/wirings/trigger/trigger.types.d.ts +130 -0
  182. package/dist/wirings/trigger/trigger.types.js +40 -0
  183. package/dist/wirings/variable/index.d.ts +3 -0
  184. package/dist/wirings/variable/index.js +2 -0
  185. package/dist/wirings/variable/validate-variable-definitions.d.ts +6 -0
  186. package/dist/wirings/variable/validate-variable-definitions.js +45 -0
  187. package/dist/wirings/variable/variable.types.d.ts +18 -0
  188. package/dist/wirings/variable/variable.types.js +1 -0
  189. package/dist/wirings/workflow/dsl/index.d.ts +5 -0
  190. package/dist/wirings/workflow/dsl/index.js +4 -0
  191. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +292 -0
  192. package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
  193. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
  194. package/dist/wirings/workflow/dsl/workflow-runner.js +23 -0
  195. package/dist/wirings/workflow/graph/graph-node.d.ts +117 -0
  196. package/dist/wirings/workflow/graph/graph-node.js +58 -0
  197. package/dist/wirings/workflow/graph/graph-runner.d.ts +9 -0
  198. package/dist/wirings/workflow/graph/graph-runner.js +540 -0
  199. package/dist/wirings/workflow/graph/index.d.ts +4 -0
  200. package/dist/wirings/workflow/graph/index.js +3 -0
  201. package/dist/wirings/workflow/graph/template.d.ts +15 -0
  202. package/dist/wirings/workflow/graph/template.js +27 -0
  203. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +15 -0
  204. package/dist/wirings/workflow/graph/wire-workflow-graph.js +8 -0
  205. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +82 -0
  206. package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
  207. package/dist/wirings/workflow/index.d.ts +7 -12
  208. package/dist/wirings/workflow/index.js +8 -11
  209. package/dist/wirings/workflow/pikku-workflow-service.d.ts +114 -10
  210. package/dist/wirings/workflow/pikku-workflow-service.js +386 -115
  211. package/dist/wirings/workflow/workflow-helpers.d.ts +36 -0
  212. package/dist/wirings/workflow/workflow-helpers.js +38 -0
  213. package/dist/wirings/workflow/workflow-utils.d.ts +1 -0
  214. package/dist/wirings/workflow/workflow-utils.js +1 -0
  215. package/dist/wirings/workflow/workflow.types.d.ts +83 -214
  216. package/package.json +13 -6
  217. package/run-tests.sh +4 -1
  218. package/src/crypto-utils.ts +99 -0
  219. package/src/errors/error-handler.ts +3 -3
  220. package/src/errors/errors.ts +17 -0
  221. package/src/errors/index.ts +0 -1
  222. package/src/factory-functions.test.ts +42 -2
  223. package/src/function/function-runner.test.ts +5 -12
  224. package/src/function/function-runner.ts +195 -40
  225. package/src/function/functions.types.ts +66 -14
  226. package/src/function/index.ts +5 -2
  227. package/src/handle-error.ts +2 -10
  228. package/src/index.ts +106 -27
  229. package/src/middleware/auth-apikey.test.ts +15 -12
  230. package/src/middleware/auth-apikey.ts +3 -3
  231. package/src/middleware/auth-bearer.test.ts +17 -14
  232. package/src/middleware/auth-bearer.ts +25 -27
  233. package/src/middleware/auth-cookie.test.ts +16 -13
  234. package/src/middleware/auth-cookie.ts +6 -8
  235. package/src/middleware/cors.ts +96 -0
  236. package/src/middleware/index.ts +5 -3
  237. package/src/middleware/remote-auth.ts +68 -0
  238. package/src/middleware-runner.test.ts +122 -0
  239. package/src/middleware-runner.ts +24 -17
  240. package/src/permissions.test.ts +102 -86
  241. package/src/permissions.ts +32 -93
  242. package/src/pikku-state.ts +168 -201
  243. package/src/run-tests-script.test.ts +49 -0
  244. package/src/schema.ts +50 -18
  245. package/src/services/ai-agent-runner-service.ts +29 -0
  246. package/src/services/ai-run-state-service.ts +20 -0
  247. package/src/services/ai-storage-service.ts +39 -0
  248. package/src/services/deployment-service.ts +22 -0
  249. package/src/services/gopass-secrets.ts +95 -0
  250. package/src/services/in-memory-trigger-service.ts +68 -0
  251. package/src/services/in-memory-workflow-service.ts +395 -0
  252. package/src/services/index.ts +49 -14
  253. package/src/services/local-secrets.ts +51 -0
  254. package/src/services/local-variables.ts +22 -0
  255. package/src/services/scheduler-service.ts +29 -1
  256. package/src/services/schema-service.ts +7 -0
  257. package/src/services/scoped-secret-service.ts +41 -0
  258. package/src/services/secret-service.ts +25 -4
  259. package/src/services/trigger-service.ts +38 -0
  260. package/src/services/typed-secret-service.ts +70 -0
  261. package/src/services/typed-variables-service.ts +81 -0
  262. package/src/services/user-session-service.ts +23 -0
  263. package/src/services/variables-service.ts +5 -0
  264. package/src/services/workflow-service.ts +94 -0
  265. package/src/types/core.types.ts +82 -8
  266. package/src/types/state.types.ts +169 -0
  267. package/src/utils.ts +74 -5
  268. package/src/version.test.ts +80 -0
  269. package/src/version.ts +25 -0
  270. package/src/wirings/ai-agent/ai-agent-memory.ts +300 -0
  271. package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
  272. package/src/wirings/ai-agent/ai-agent-prepare.ts +470 -0
  273. package/src/wirings/ai-agent/ai-agent-registry.test.ts +37 -0
  274. package/src/wirings/ai-agent/ai-agent-registry.ts +82 -0
  275. package/src/wirings/ai-agent/ai-agent-runner.test.ts +75 -0
  276. package/src/wirings/ai-agent/ai-agent-runner.ts +137 -0
  277. package/src/wirings/ai-agent/ai-agent-stream.test.ts +246 -0
  278. package/src/wirings/ai-agent/ai-agent-stream.ts +774 -0
  279. package/src/wirings/ai-agent/ai-agent.types.ts +273 -0
  280. package/src/wirings/ai-agent/index.ts +28 -0
  281. package/src/wirings/channel/channel-common.ts +32 -19
  282. package/src/wirings/channel/channel-handler.ts +18 -5
  283. package/src/wirings/channel/channel-middleware-runner.ts +119 -0
  284. package/src/wirings/channel/channel-runner.ts +14 -15
  285. package/src/wirings/channel/channel.types.ts +17 -1
  286. package/src/wirings/channel/define-channel-routes.ts +25 -0
  287. package/src/wirings/channel/index.ts +23 -8
  288. package/src/wirings/channel/local/index.ts +3 -3
  289. package/src/wirings/channel/local/local-channel-runner.test.ts +47 -2
  290. package/src/wirings/channel/local/local-channel-runner.ts +22 -6
  291. package/src/wirings/channel/log-channels.ts +1 -1
  292. package/src/wirings/channel/serverless/index.ts +5 -1
  293. package/src/wirings/channel/serverless/serverless-channel-runner.ts +22 -6
  294. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
  295. package/src/wirings/cli/channel/index.ts +1 -1
  296. package/src/wirings/cli/cli-runner.test.ts +28 -28
  297. package/src/wirings/cli/cli-runner.ts +27 -19
  298. package/src/wirings/cli/cli.types.ts +12 -11
  299. package/src/wirings/cli/command-parser.test.ts +8 -8
  300. package/src/wirings/cli/define-cli-commands.ts +24 -0
  301. package/src/wirings/cli/index.ts +10 -4
  302. package/src/wirings/http/http-routes.test.ts +322 -0
  303. package/src/wirings/http/http-routes.ts +198 -0
  304. package/src/wirings/http/http-runner.test.ts +5 -5
  305. package/src/wirings/http/http-runner.ts +80 -29
  306. package/src/wirings/http/http.types.ts +121 -23
  307. package/src/wirings/http/index.ts +16 -4
  308. package/src/wirings/http/log-http-routes.ts +1 -1
  309. package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
  310. package/src/wirings/http/routers/path-to-regex.ts +2 -2
  311. package/src/wirings/mcp/index.ts +27 -3
  312. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +3 -3
  313. package/src/wirings/mcp/mcp-runner.ts +56 -67
  314. package/src/wirings/mcp/mcp.types.ts +3 -3
  315. package/src/wirings/node/index.ts +2 -0
  316. package/src/wirings/node/node.types.ts +23 -0
  317. package/src/wirings/oauth2/index.ts +3 -0
  318. package/src/wirings/oauth2/oauth2-client.test.ts +929 -0
  319. package/src/wirings/oauth2/oauth2-client.ts +335 -0
  320. package/src/wirings/oauth2/oauth2.types.ts +69 -0
  321. package/src/wirings/oauth2/wire-oauth2-credential.ts +23 -0
  322. package/src/wirings/queue/index.ts +14 -2
  323. package/src/wirings/queue/queue-runner.test.ts +115 -73
  324. package/src/wirings/queue/queue-runner.ts +39 -13
  325. package/src/wirings/queue/queue.types.ts +12 -2
  326. package/src/wirings/rpc/index.ts +1 -1
  327. package/src/wirings/rpc/rpc-runner.ts +270 -34
  328. package/src/wirings/rpc/rpc-types.ts +21 -4
  329. package/src/wirings/scheduler/index.ts +7 -4
  330. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  331. package/src/wirings/scheduler/scheduler-runner.test.ts +97 -53
  332. package/src/wirings/scheduler/scheduler-runner.ts +50 -10
  333. package/src/wirings/secret/index.ts +9 -0
  334. package/src/wirings/secret/secret.types.ts +32 -0
  335. package/src/wirings/secret/validate-secret-definitions.ts +82 -0
  336. package/src/wirings/trigger/index.ts +10 -0
  337. package/src/wirings/trigger/pikku-trigger-service.ts +134 -0
  338. package/src/wirings/trigger/trigger-runner.ts +138 -0
  339. package/src/wirings/trigger/trigger.types.ts +178 -0
  340. package/src/wirings/variable/index.ts +8 -0
  341. package/src/wirings/variable/validate-variable-definitions.ts +69 -0
  342. package/src/wirings/variable/variable.types.ts +22 -0
  343. package/src/wirings/workflow/dsl/index.ts +31 -0
  344. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +320 -0
  345. package/src/wirings/workflow/dsl/workflow-runner.ts +28 -0
  346. package/src/wirings/workflow/graph/graph-node.ts +222 -0
  347. package/src/wirings/workflow/graph/graph-runner.test.ts +495 -0
  348. package/src/wirings/workflow/graph/graph-runner.ts +816 -0
  349. package/src/wirings/workflow/graph/index.ts +14 -0
  350. package/src/wirings/workflow/graph/template.ts +42 -0
  351. package/src/wirings/workflow/graph/wire-workflow-graph.ts +29 -0
  352. package/src/wirings/workflow/graph/workflow-graph.types.ts +104 -0
  353. package/src/wirings/workflow/index.ts +64 -26
  354. package/src/wirings/workflow/pikku-workflow-service.test.ts +212 -0
  355. package/src/wirings/workflow/pikku-workflow-service.ts +571 -136
  356. package/src/wirings/workflow/workflow-helpers.ts +79 -0
  357. package/src/wirings/workflow/workflow-utils.ts +0 -0
  358. package/src/wirings/workflow/workflow.types.ts +123 -279
  359. package/tsconfig.tsbuildinfo +1 -1
  360. package/dist/wirings/workflow/workflow-runner.d.ts +0 -34
  361. package/dist/wirings/workflow/workflow-runner.js +0 -65
  362. package/src/function/function-runner.ts.bak +0 -188
  363. package/src/wirings/workflow/workflow-runner.ts +0 -72
@@ -2,8 +2,8 @@ import { getErrorResponse } from '../../errors/error-handler.js';
2
2
  import { closeWireServices } from '../../utils.js';
3
3
  import { pikkuState } from '../../pikku-state.js';
4
4
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
5
- import { BadRequestError, NotFoundError } from '../../errors/errors.js';
6
- import { PikkuSessionService } from '../../services/user-session-service.js';
5
+ import { BadRequestError, NotFoundError, PikkuMissingMetaError, } from '../../errors/errors.js';
6
+ import { PikkuSessionService, createMiddlewareSessionWireProps, } from '../../services/user-session-service.js';
7
7
  export class MCPError extends Error {
8
8
  error;
9
9
  constructor(error) {
@@ -14,39 +14,26 @@ export class MCPError extends Error {
14
14
  }
15
15
  }
16
16
  export const wireMCPResource = (mcpResource) => {
17
- const resourcesMeta = pikkuState('mcp', 'resourcesMeta');
17
+ const resourcesMeta = pikkuState(null, 'mcp', 'resourcesMeta');
18
18
  const mcpResourceMeta = resourcesMeta[mcpResource.uri];
19
19
  if (!mcpResourceMeta) {
20
- throw new Error(`MCP resource metadata not found for '${mcpResource.uri}'`);
20
+ throw new PikkuMissingMetaError(`Missing generated metadata for MCP resource '${mcpResource.uri}'`);
21
21
  }
22
- addFunction(mcpResourceMeta.pikkuFuncName, mcpResource.func);
23
- const resources = pikkuState('mcp', 'resources');
22
+ addFunction(mcpResourceMeta.pikkuFuncId, mcpResource.func);
23
+ const resources = pikkuState(null, 'mcp', 'resources');
24
24
  if (resources.has(mcpResource.uri)) {
25
25
  throw new Error(`MCP resource already exists: ${mcpResource.uri}`);
26
26
  }
27
27
  resources.set(mcpResource.uri, mcpResource);
28
28
  };
29
- export const wireMCPTool = (mcpTool) => {
30
- const toolsMeta = pikkuState('mcp', 'toolsMeta');
31
- const mcpToolMeta = toolsMeta[mcpTool.name];
32
- if (!mcpToolMeta) {
33
- throw new Error(`MCP tool metadata not found for '${mcpTool.name}'`);
34
- }
35
- addFunction(mcpToolMeta.pikkuFuncName, mcpTool.func);
36
- const tools = pikkuState('mcp', 'tools');
37
- if (tools.has(mcpTool.name)) {
38
- throw new Error(`MCP tool already exists: ${mcpTool.name}`);
39
- }
40
- tools.set(mcpTool.name, mcpTool);
41
- };
42
29
  export const wireMCPPrompt = (mcpPrompt) => {
43
- const promptsMeta = pikkuState('mcp', 'promptsMeta');
30
+ const promptsMeta = pikkuState(null, 'mcp', 'promptsMeta');
44
31
  const mcpPromptMeta = promptsMeta[mcpPrompt.name];
45
32
  if (!mcpPromptMeta) {
46
- throw new Error(`MCP prompt metadata not found for '${mcpPrompt.name}'`);
33
+ throw new PikkuMissingMetaError(`Missing generated metadata for MCP prompt '${mcpPrompt.name}'`);
47
34
  }
48
- addFunction(mcpPromptMeta.pikkuFuncName, mcpPrompt.func);
49
- const prompts = pikkuState('mcp', 'prompts');
35
+ addFunction(mcpPromptMeta.pikkuFuncId, mcpPrompt.func);
36
+ const prompts = pikkuState(null, 'mcp', 'prompts');
50
37
  if (prompts.has(mcpPrompt.name)) {
51
38
  throw new Error(`MCP prompt already exists: ${mcpPrompt.name}`);
52
39
  }
@@ -54,13 +41,13 @@ export const wireMCPPrompt = (mcpPrompt) => {
54
41
  };
55
42
  export async function runMCPResource(request, params, uri) {
56
43
  let endpoint;
57
- let pikkuFuncName;
44
+ let pikkuFuncId;
58
45
  let extractedParams = {};
59
- const metas = pikkuState('mcp', 'resourcesMeta');
60
- const endpoints = pikkuState('mcp', 'resources');
46
+ const metas = pikkuState(null, 'mcp', 'resourcesMeta');
47
+ const endpoints = pikkuState(null, 'mcp', 'resources');
61
48
  if (endpoints.has(uri)) {
62
49
  endpoint = endpoints.get(uri);
63
- pikkuFuncName = metas[uri]?.pikkuFuncName;
50
+ pikkuFuncId = metas[uri]?.pikkuFuncId;
64
51
  }
65
52
  else {
66
53
  for (const [uriTemplate, value] of endpoints.entries()) {
@@ -72,7 +59,7 @@ export async function runMCPResource(request, params, uri) {
72
59
  const match = uri.match(regex);
73
60
  if (match) {
74
61
  endpoint = value;
75
- pikkuFuncName = metas[uriTemplate]?.pikkuFuncName;
62
+ pikkuFuncId = metas[uriTemplate]?.pikkuFuncId;
76
63
  // Extract parameter values and create params object
77
64
  for (let i = 0; i < paramNames.length; i++) {
78
65
  extractedParams[paramNames[i]] = match[i + 1]; // match[0] is the full match
@@ -84,61 +71,63 @@ export async function runMCPResource(request, params, uri) {
84
71
  return await runMCPPikkuFunc({
85
72
  ...request,
86
73
  params: { ...request.params, ...extractedParams },
87
- }, 'resource', uri, endpoint, pikkuFuncName, { ...params, mcp: { ...params.mcp, uri } });
74
+ }, 'resource', uri, endpoint, pikkuFuncId, { ...params, mcp: { ...params.mcp, uri } });
88
75
  }
89
76
  export async function runMCPTool(request, params, name) {
90
- const endpoint = pikkuState('mcp', 'tools').get(name);
91
- const meta = pikkuState('mcp', 'toolsMeta')[name];
92
- return await runMCPPikkuFunc(request, 'tool', name, endpoint, meta?.pikkuFuncName, params);
77
+ const meta = pikkuState(null, 'mcp', 'toolsMeta')[name];
78
+ return await runMCPPikkuFunc(request, 'tool', name, undefined, meta?.pikkuFuncId, params);
93
79
  }
94
80
  export async function runMCPPrompt(request, params, name) {
95
- const endpoint = pikkuState('mcp', 'prompts').get(name);
96
- const meta = pikkuState('mcp', 'promptsMeta')[name];
97
- return await runMCPPikkuFunc(request, 'prompt', name, endpoint, meta?.pikkuFuncName, params);
81
+ const endpoint = pikkuState(null, 'mcp', 'prompts').get(name);
82
+ const meta = pikkuState(null, 'mcp', 'promptsMeta')[name];
83
+ return await runMCPPikkuFunc(request, 'prompt', name, endpoint, meta?.pikkuFuncId, params);
98
84
  }
99
85
  /**
100
86
  * JSON-RPC 2.0 compatible MCP endpoint runner
101
87
  */
102
- async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { singletonServices, createWireServices, mcp: mcpWire }) {
88
+ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncId, { singletonServices, createWireServices, mcp: mcpWire }) {
103
89
  let wireServices;
104
90
  try {
105
- // Validate JSON-RPC request structure
106
91
  if (request.jsonrpc !== '2.0') {
107
92
  throw new BadRequestError('Invalid JSON-RPC version, only supoorted version is 2.0');
108
93
  }
109
- if (!mcp) {
94
+ if (mcp === undefined && type !== 'tool') {
110
95
  throw new NotFoundError(`MCP '${type}' registration not found for '${name}'`);
111
96
  }
112
- if (!pikkuFuncName) {
97
+ if (!pikkuFuncId) {
113
98
  throw new NotFoundError(`MCP '${type}' PikkuFunction Mapping not found for '${name}'`);
114
99
  }
115
100
  singletonServices.logger.debug(`Running MCP ${type}: ${name}`);
101
+ const mcpSessionService = new PikkuSessionService();
116
102
  const wire = {
117
103
  mcp: mcpWire,
118
- session: new PikkuSessionService(),
104
+ ...createMiddlewareSessionWireProps(mcpSessionService),
119
105
  };
120
- // Get metadata for the MCP endpoint to access pre-resolved middleware
121
106
  let meta;
122
107
  if (type === 'resource') {
123
- meta = pikkuState('mcp', 'resourcesMeta')[name];
108
+ meta = pikkuState(null, 'mcp', 'resourcesMeta')[name];
124
109
  }
125
110
  else if (type === 'tool') {
126
- meta = pikkuState('mcp', 'toolsMeta')[name];
111
+ meta = pikkuState(null, 'mcp', 'toolsMeta')[name];
127
112
  }
128
113
  else if (type === 'prompt') {
129
- meta = pikkuState('mcp', 'promptsMeta')[name];
114
+ meta = pikkuState(null, 'mcp', 'promptsMeta')[name];
130
115
  }
131
- const result = await runPikkuFunc('mcp', `${type}:${name}`, pikkuFuncName, {
116
+ let result = await runPikkuFunc('mcp', `${type}:${name}`, pikkuFuncId, {
132
117
  singletonServices,
133
118
  createWireServices,
134
119
  data: () => request.params,
135
120
  inheritedMiddleware: meta?.middleware,
136
- wireMiddleware: mcp.middleware,
121
+ wireMiddleware: mcp?.middleware,
137
122
  inheritedPermissions: meta?.permissions,
138
- wirePermissions: mcp.permissions,
139
- tags: mcp.tags,
123
+ wirePermissions: mcp?.permissions,
124
+ tags: mcp?.tags,
140
125
  wire,
126
+ sessionService: mcpSessionService,
141
127
  });
128
+ if (type === 'tool' && meta?.outputSchema !== 'MCPToolResponse') {
129
+ result = [{ type: 'text', text: JSON.stringify(result) }];
130
+ }
142
131
  return {
143
132
  id: request.id,
144
133
  result,
@@ -172,21 +161,18 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { single
172
161
  }
173
162
  }
174
163
  }
175
- export const getMCPTools = () => {
176
- return pikkuState('mcp', 'tools');
177
- };
178
164
  export const getMCPResources = () => {
179
- return pikkuState('mcp', 'resources');
165
+ return pikkuState(null, 'mcp', 'resources');
180
166
  };
181
167
  export const getMCPResourcesMeta = () => {
182
- return pikkuState('mcp', 'resourcesMeta');
168
+ return pikkuState(null, 'mcp', 'resourcesMeta');
183
169
  };
184
170
  export const getMCPToolsMeta = () => {
185
- return pikkuState('mcp', 'toolsMeta');
171
+ return pikkuState(null, 'mcp', 'toolsMeta');
186
172
  };
187
173
  export const getMCPPrompts = () => {
188
- return pikkuState('mcp', 'prompts');
174
+ return pikkuState(null, 'mcp', 'prompts');
189
175
  };
190
176
  export const getMCPPromptsMeta = () => {
191
- return pikkuState('mcp', 'promptsMeta');
177
+ return pikkuState(null, 'mcp', 'promptsMeta');
192
178
  };
@@ -26,7 +26,7 @@ export type PikkuMCP<Tools extends string = any> = {
26
26
  * Represents metadata for MCP resources, including name, description, and documentation.
27
27
  */
28
28
  export type MCPResourceMeta = Record<string, Omit<CoreMCPResource, 'func' | 'middleware' | 'permissions'> & {
29
- pikkuFuncName: string;
29
+ pikkuFuncId: string;
30
30
  inputSchema: string | null;
31
31
  outputSchema: string | null;
32
32
  middleware?: MiddlewareMetadata[];
@@ -36,7 +36,7 @@ export type MCPResourceMeta = Record<string, Omit<CoreMCPResource, 'func' | 'mid
36
36
  * Represents metadata for MCP tools, including name, description, and documentation.
37
37
  */
38
38
  export type MCPToolMeta = Record<string, Omit<CoreMCPTool, 'func' | 'middleware' | 'permissions'> & {
39
- pikkuFuncName: string;
39
+ pikkuFuncId: string;
40
40
  inputSchema: string | null;
41
41
  outputSchema: string | null;
42
42
  middleware?: MiddlewareMetadata[];
@@ -46,7 +46,7 @@ export type MCPToolMeta = Record<string, Omit<CoreMCPTool, 'func' | 'middleware'
46
46
  * Represents metadata for MCP prompts, including name, description, and arguments.
47
47
  */
48
48
  export type MCPPromptMeta = Record<string, Omit<CoreMCPPrompt, 'func' | 'middleware' | 'permissions'> & {
49
- pikkuFuncName: string;
49
+ pikkuFuncId: string;
50
50
  inputSchema: string | null;
51
51
  outputSchema: string | null;
52
52
  arguments: Array<{
@@ -0,0 +1,2 @@
1
+ export type { CoreNodeConfig, NodeType } from './node.types.js';
2
+ export type { NodesMeta } from './node.types.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ export type NodeType = 'trigger' | 'action' | 'end';
2
+ export type CoreNodeConfig = {
3
+ displayName: string;
4
+ category: string;
5
+ type: NodeType;
6
+ errorOutput?: boolean;
7
+ };
8
+ export type NodeMeta = {
9
+ name: string;
10
+ displayName: string;
11
+ category: string;
12
+ type: NodeType;
13
+ rpc: string;
14
+ description?: string;
15
+ errorOutput: boolean;
16
+ inputSchemaName: string | null;
17
+ outputSchemaName: string | null;
18
+ tags?: string[];
19
+ };
20
+ export type NodesMeta = Record<string, NodeMeta>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export { OAuth2Client } from './oauth2-client.js';
2
+ export { wireOAuth2Credential } from './wire-oauth2-credential.js';
3
+ export type { OAuth2AppCredential, OAuth2Token } from './oauth2.types.js';
@@ -0,0 +1,2 @@
1
+ export { OAuth2Client } from './oauth2-client.js';
2
+ export { wireOAuth2Credential } from './wire-oauth2-credential.js';
@@ -0,0 +1,47 @@
1
+ import { OAuth2Token } from './oauth2.types.js';
2
+ import { OAuth2CredentialConfig } from '../secret/secret.types.js';
3
+ import { SecretService } from '../../services/secret-service.js';
4
+ export declare class OAuth2Client {
5
+ private oauth2Config;
6
+ private appCredentialSecretId;
7
+ private secrets;
8
+ private cachedToken;
9
+ private cachedAppCredential;
10
+ private refreshPromise;
11
+ constructor(oauth2Config: OAuth2CredentialConfig, appCredentialSecretId: string, secrets: SecretService);
12
+ /**
13
+ * Make an authenticated request. Handles token caching and 401 refresh.
14
+ */
15
+ request(url: string, options?: RequestInit, timeoutMs?: number): Promise<Response>;
16
+ /**
17
+ * Get cached token or load from secrets.
18
+ */
19
+ getAccessToken(): Promise<string>;
20
+ /**
21
+ * Refresh token and update cache.
22
+ * Uses a promise lock to prevent concurrent refresh attempts.
23
+ */
24
+ private refreshAndGetToken;
25
+ /**
26
+ * Perform the actual token refresh.
27
+ */
28
+ private doRefreshToken;
29
+ /**
30
+ * Check if token is valid (not expired).
31
+ */
32
+ private isTokenValid;
33
+ /**
34
+ * Get app credentials (cached).
35
+ */
36
+ private getAppCredential;
37
+ /**
38
+ * Generate OAuth2 authorization URL.
39
+ * Used by CLI during `pikku oauth connect`.
40
+ */
41
+ getAuthorizationUrl(state: string, redirectUri: string): Promise<string>;
42
+ /**
43
+ * Exchange authorization code for tokens.
44
+ * Used by CLI during `pikku oauth connect`.
45
+ */
46
+ exchangeCode(code: string, redirectUri: string): Promise<OAuth2Token>;
47
+ }
@@ -0,0 +1,267 @@
1
+ /**
2
+ * OAuth2 client that acts as a service.
3
+ * Created once in createSingletonServices, handles token caching and refresh internally.
4
+ * Functions use it directly via oauth.request().
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // In services.ts
9
+ * export const createSingletonServices = async (config, { secrets }) => {
10
+ * return {
11
+ * slackOAuth: new OAuth2Client(
12
+ * { tokenSecretId: 'SLACK_TOKENS', authorizationUrl: '...', tokenUrl: '...', scopes: [] },
13
+ * 'SLACK_APP_CREDS',
14
+ * secrets
15
+ * ),
16
+ * }
17
+ * }
18
+ *
19
+ * // In function
20
+ * export const postMessage = pikkuFunc(async ({ slackOAuth }, { channel, text }) => {
21
+ * const response = await slackOAuth.request('https://slack.com/api/chat.postMessage', {
22
+ * method: 'POST',
23
+ * body: JSON.stringify({ channel, text }),
24
+ * })
25
+ * return response.json()
26
+ * })
27
+ * ```
28
+ */
29
+ const DEFAULT_TIMEOUT_MS = 30000;
30
+ /**
31
+ * Helper to fetch with a timeout using AbortController.
32
+ */
33
+ async function fetchWithTimeout(url, options, timeoutMs = DEFAULT_TIMEOUT_MS) {
34
+ const controller = new AbortController();
35
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
36
+ try {
37
+ return await fetch(url, {
38
+ ...options,
39
+ signal: controller.signal,
40
+ });
41
+ }
42
+ finally {
43
+ clearTimeout(timeoutId);
44
+ }
45
+ }
46
+ export class OAuth2Client {
47
+ oauth2Config;
48
+ appCredentialSecretId;
49
+ secrets;
50
+ cachedToken = null;
51
+ cachedAppCredential = null;
52
+ refreshPromise = null;
53
+ constructor(oauth2Config, appCredentialSecretId, secrets) {
54
+ this.oauth2Config = oauth2Config;
55
+ this.appCredentialSecretId = appCredentialSecretId;
56
+ this.secrets = secrets;
57
+ }
58
+ /**
59
+ * Make an authenticated request. Handles token caching and 401 refresh.
60
+ */
61
+ async request(url, options, timeoutMs = DEFAULT_TIMEOUT_MS) {
62
+ const token = await this.getAccessToken();
63
+ const response = await fetchWithTimeout(url, {
64
+ ...options,
65
+ headers: {
66
+ ...options?.headers,
67
+ Authorization: `Bearer ${token}`,
68
+ },
69
+ }, timeoutMs);
70
+ // Auto-retry on 401 after refresh
71
+ if (response.status === 401) {
72
+ const newToken = await this.refreshAndGetToken();
73
+ return fetchWithTimeout(url, {
74
+ ...options,
75
+ headers: {
76
+ ...options?.headers,
77
+ Authorization: `Bearer ${newToken}`,
78
+ },
79
+ }, timeoutMs);
80
+ }
81
+ return response;
82
+ }
83
+ /**
84
+ * Get cached token or load from secrets.
85
+ */
86
+ async getAccessToken() {
87
+ // Return cached token if valid
88
+ if (this.cachedToken) {
89
+ if (this.isTokenValid(this.cachedToken)) {
90
+ return this.cachedToken.accessToken;
91
+ }
92
+ // Token expired, try to refresh
93
+ if (this.cachedToken.refreshToken) {
94
+ return this.refreshAndGetToken();
95
+ }
96
+ // Token expired and no refresh token available
97
+ throw new Error('OAuth2 token expired and no refresh token available');
98
+ }
99
+ // Load from secrets
100
+ const token = await this.secrets.getSecretJSON(this.oauth2Config.tokenSecretId);
101
+ this.cachedToken = token;
102
+ // Check if loaded token is expired and needs refresh
103
+ if (!this.isTokenValid(token)) {
104
+ if (token.refreshToken) {
105
+ return this.refreshAndGetToken();
106
+ }
107
+ // Token expired and no refresh token available
108
+ throw new Error('OAuth2 token expired and no refresh token available');
109
+ }
110
+ return token.accessToken;
111
+ }
112
+ /**
113
+ * Refresh token and update cache.
114
+ * Uses a promise lock to prevent concurrent refresh attempts.
115
+ */
116
+ async refreshAndGetToken() {
117
+ // If already refreshing, wait for that to complete
118
+ if (this.refreshPromise) {
119
+ const token = await this.refreshPromise;
120
+ return token.accessToken;
121
+ }
122
+ // Start refresh
123
+ this.refreshPromise = this.doRefreshToken();
124
+ try {
125
+ const token = await this.refreshPromise;
126
+ this.cachedToken = token;
127
+ return token.accessToken;
128
+ }
129
+ finally {
130
+ this.refreshPromise = null;
131
+ }
132
+ }
133
+ /**
134
+ * Perform the actual token refresh.
135
+ */
136
+ async doRefreshToken() {
137
+ if (!this.cachedToken?.refreshToken) {
138
+ throw new Error('No refresh token available');
139
+ }
140
+ const appCredential = await this.getAppCredential();
141
+ const params = new URLSearchParams({
142
+ grant_type: 'refresh_token',
143
+ refresh_token: this.cachedToken.refreshToken,
144
+ client_id: appCredential.clientId,
145
+ });
146
+ if (appCredential.clientSecret) {
147
+ params.set('client_secret', appCredential.clientSecret);
148
+ }
149
+ const response = await fetchWithTimeout(this.oauth2Config.tokenUrl, {
150
+ method: 'POST',
151
+ headers: {
152
+ 'Content-Type': 'application/x-www-form-urlencoded',
153
+ },
154
+ body: params.toString(),
155
+ });
156
+ if (!response.ok) {
157
+ throw new Error(`Token refresh failed: ${response.status}`);
158
+ }
159
+ const data = await response.json();
160
+ if (!data.access_token || typeof data.access_token !== 'string') {
161
+ throw new Error('Invalid token response: missing access_token');
162
+ }
163
+ const token = {
164
+ accessToken: data.access_token,
165
+ refreshToken: data.refresh_token || this.cachedToken.refreshToken,
166
+ expiresAt: data.expires_in
167
+ ? Date.now() + data.expires_in * 1000
168
+ : undefined,
169
+ tokenType: data.token_type || 'Bearer',
170
+ scope: data.scope,
171
+ };
172
+ // Cache and persist the refreshed token
173
+ this.cachedToken = token;
174
+ await this.secrets.setSecretJSON(this.oauth2Config.tokenSecretId, token);
175
+ return token;
176
+ }
177
+ /**
178
+ * Check if token is valid (not expired).
179
+ */
180
+ isTokenValid(token) {
181
+ if (!token.expiresAt) {
182
+ return true; // No expiry info, assume valid
183
+ }
184
+ // Add 60 second buffer to account for clock skew
185
+ return token.expiresAt > Date.now() + 60000;
186
+ }
187
+ /**
188
+ * Get app credentials (cached).
189
+ */
190
+ async getAppCredential() {
191
+ if (this.cachedAppCredential) {
192
+ return this.cachedAppCredential;
193
+ }
194
+ this.cachedAppCredential =
195
+ await this.secrets.getSecretJSON(this.appCredentialSecretId);
196
+ return this.cachedAppCredential;
197
+ }
198
+ // ========================================
199
+ // CLI-only methods (for pikku oauth connect)
200
+ // ========================================
201
+ /**
202
+ * Generate OAuth2 authorization URL.
203
+ * Used by CLI during `pikku oauth connect`.
204
+ */
205
+ async getAuthorizationUrl(state, redirectUri) {
206
+ const appCredential = await this.getAppCredential();
207
+ const params = new URLSearchParams({
208
+ response_type: 'code',
209
+ client_id: appCredential.clientId,
210
+ redirect_uri: redirectUri,
211
+ scope: this.oauth2Config.scopes.join(' '),
212
+ state,
213
+ });
214
+ // Add PKCE if enabled
215
+ // Note: code_verifier should be stored and passed to exchangeCode
216
+ // For now, PKCE implementation is simplified
217
+ // Add any additional params
218
+ if (this.oauth2Config.additionalParams) {
219
+ for (const [key, value] of Object.entries(this.oauth2Config.additionalParams)) {
220
+ params.set(key, value);
221
+ }
222
+ }
223
+ return `${this.oauth2Config.authorizationUrl}?${params.toString()}`;
224
+ }
225
+ /**
226
+ * Exchange authorization code for tokens.
227
+ * Used by CLI during `pikku oauth connect`.
228
+ */
229
+ async exchangeCode(code, redirectUri) {
230
+ const appCredential = await this.getAppCredential();
231
+ const params = new URLSearchParams({
232
+ grant_type: 'authorization_code',
233
+ code,
234
+ redirect_uri: redirectUri,
235
+ client_id: appCredential.clientId,
236
+ });
237
+ if (appCredential.clientSecret) {
238
+ params.set('client_secret', appCredential.clientSecret);
239
+ }
240
+ const response = await fetchWithTimeout(this.oauth2Config.tokenUrl, {
241
+ method: 'POST',
242
+ headers: {
243
+ 'Content-Type': 'application/x-www-form-urlencoded',
244
+ },
245
+ body: params.toString(),
246
+ });
247
+ if (!response.ok) {
248
+ throw new Error(`Token exchange failed: ${response.status}`);
249
+ }
250
+ const data = await response.json();
251
+ if (!data.access_token || typeof data.access_token !== 'string') {
252
+ throw new Error('Invalid token response: missing access_token');
253
+ }
254
+ const token = {
255
+ accessToken: data.access_token,
256
+ refreshToken: data.refresh_token,
257
+ expiresAt: data.expires_in
258
+ ? Date.now() + data.expires_in * 1000
259
+ : undefined,
260
+ tokenType: data.token_type || 'Bearer',
261
+ scope: data.scope,
262
+ };
263
+ // Cache the token
264
+ this.cachedToken = token;
265
+ return token;
266
+ }
267
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * OAuth2 credential and token types.
3
+ */
4
+ /**
5
+ * App credentials for OAuth2 (client ID and secret).
6
+ * These are typically set once and stored in the secret service.
7
+ */
8
+ export type OAuth2AppCredential = {
9
+ clientId: string;
10
+ clientSecret?: string;
11
+ };
12
+ /**
13
+ * OAuth2 token data returned from token endpoint.
14
+ */
15
+ export type OAuth2Token = {
16
+ accessToken: string;
17
+ refreshToken?: string;
18
+ expiresAt?: number;
19
+ tokenType: string;
20
+ scope?: string;
21
+ };
22
+ /**
23
+ * OAuth2-specific configuration that extends a credential.
24
+ * This is stored in SecretDefinitionMeta.oauth2 field.
25
+ */
26
+ export type OAuth2Config = {
27
+ /** Where access/refresh tokens are stored */
28
+ tokenSecretId: string;
29
+ /** OAuth2 authorization URL */
30
+ authorizationUrl: string;
31
+ /** OAuth2 token exchange URL */
32
+ tokenUrl: string;
33
+ /** Required scopes */
34
+ scopes: string[];
35
+ /** Use PKCE flow */
36
+ pkce?: boolean;
37
+ /** Additional query parameters for authorization URL */
38
+ additionalParams?: Record<string, string>;
39
+ };
40
+ /**
41
+ * Configuration for wireOAuth2Credential.
42
+ * Combines standard credential fields with OAuth2-specific config.
43
+ */
44
+ export type CoreOAuth2Credential = {
45
+ /** Unique identifier for this credential */
46
+ name: string;
47
+ /** Human-readable name for UI display */
48
+ displayName: string;
49
+ /** Optional description for UI */
50
+ description?: string;
51
+ /** Key used with SecretService to retrieve app credentials (clientId/clientSecret) */
52
+ secretId: string;
53
+ /** Where access/refresh tokens are stored */
54
+ tokenSecretId: string;
55
+ /** OAuth2 authorization URL */
56
+ authorizationUrl: string;
57
+ /** OAuth2 token exchange URL */
58
+ tokenUrl: string;
59
+ /** Required scopes */
60
+ scopes: string[];
61
+ /** Use PKCE flow */
62
+ pkce?: boolean;
63
+ /** Additional query parameters for authorization URL */
64
+ additionalParams?: Record<string, string>;
65
+ };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * OAuth2 credential and token types.
3
+ */
4
+ export {};
@@ -0,0 +1,20 @@
1
+ import { CoreOAuth2Credential } from './oauth2.types.js';
2
+ /**
3
+ * No-op function for declaring OAuth2 credentials.
4
+ * This exists purely for TypeScript type checking and will be tree-shaken.
5
+ * The CLI extracts metadata via AST parsing.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * wireOAuth2Credential({
10
+ * name: 'slackOAuth',
11
+ * displayName: 'Slack OAuth',
12
+ * secretId: 'SLACK_OAUTH_APP',
13
+ * tokenSecretId: 'SLACK_OAUTH_TOKENS',
14
+ * authorizationUrl: 'https://slack.com/oauth/v2/authorize',
15
+ * tokenUrl: 'https://slack.com/api/oauth.v2.access',
16
+ * scopes: ['chat:write', 'channels:read'],
17
+ * })
18
+ * ```
19
+ */
20
+ export declare const wireOAuth2Credential: (_config: CoreOAuth2Credential) => void;