@pikku/core 0.12.0 → 0.12.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 (290) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/errors/errors.d.ts +6 -0
  3. package/dist/errors/errors.js +10 -0
  4. package/dist/errors/index.d.ts +1 -0
  5. package/dist/errors/index.js +1 -0
  6. package/dist/function/function-runner.d.ts +3 -3
  7. package/dist/function/function-runner.js +66 -44
  8. package/dist/function/functions.types.d.ts +1 -0
  9. package/dist/handle-error.d.ts +2 -2
  10. package/dist/handle-error.js +2 -2
  11. package/dist/index.d.ts +5 -3
  12. package/dist/index.js +2 -1
  13. package/dist/internal.d.ts +3 -0
  14. package/dist/internal.js +2 -0
  15. package/dist/middleware/auth-bearer.d.ts +1 -1
  16. package/dist/middleware/auth-bearer.js +1 -1
  17. package/dist/middleware/auth-cookie.d.ts +2 -2
  18. package/dist/middleware/auth-cookie.js +1 -1
  19. package/dist/middleware/cors.d.ts +2 -2
  20. package/dist/middleware/cors.js +45 -37
  21. package/dist/middleware-runner.d.ts +1 -1
  22. package/dist/middleware-runner.js +1 -0
  23. package/dist/permissions.d.ts +2 -2
  24. package/dist/permissions.js +1 -0
  25. package/dist/pikku-state.d.ts +9 -8
  26. package/dist/pikku-state.js +34 -17
  27. package/dist/schema.d.ts +4 -4
  28. package/dist/schema.js +9 -5
  29. package/dist/services/ai-agent-runner-service.d.ts +22 -3
  30. package/dist/services/ai-run-state-service.d.ts +1 -1
  31. package/dist/services/ai-storage-service.d.ts +1 -1
  32. package/dist/services/content-service.d.ts +6 -0
  33. package/dist/services/gateway-service.d.ts +19 -0
  34. package/dist/services/gopass-secrets.d.ts +1 -1
  35. package/dist/services/gopass-secrets.js +3 -0
  36. package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
  37. package/dist/services/in-memory-ai-run-state-service.js +44 -0
  38. package/dist/services/in-memory-trigger-service.d.ts +0 -1
  39. package/dist/services/in-memory-trigger-service.js +6 -8
  40. package/dist/services/index.d.ts +5 -2
  41. package/dist/services/index.js +2 -0
  42. package/dist/services/local-content.d.ts +2 -1
  43. package/dist/services/local-content.js +6 -1
  44. package/dist/services/local-gateway-service.d.ts +22 -0
  45. package/dist/services/local-gateway-service.js +51 -0
  46. package/dist/services/local-secrets.d.ts +2 -2
  47. package/dist/services/local-variables.d.ts +1 -1
  48. package/dist/services/logger-console.d.ts +2 -1
  49. package/dist/services/scheduler-service.d.ts +0 -12
  50. package/dist/services/scheduler-service.js +0 -6
  51. package/dist/services/scoped-secret-service.d.ts +1 -1
  52. package/dist/services/trigger-service.d.ts +0 -7
  53. package/dist/services/user-session-service.d.ts +3 -3
  54. package/dist/services/workflow-service.d.ts +2 -3
  55. package/dist/types/core.types.d.ts +27 -19
  56. package/dist/types/state.types.d.ts +22 -15
  57. package/dist/utils.d.ts +5 -5
  58. package/dist/utils.js +12 -9
  59. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
  60. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +168 -0
  61. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
  62. package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
  63. package/dist/wirings/ai-agent/ai-agent-memory.js +13 -2
  64. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +4 -5
  65. package/dist/wirings/ai-agent/ai-agent-prepare.js +80 -31
  66. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +1 -1
  67. package/dist/wirings/ai-agent/ai-agent-runner.js +107 -8
  68. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +2 -1
  69. package/dist/wirings/ai-agent/ai-agent-stream.js +263 -89
  70. package/dist/wirings/ai-agent/ai-agent.types.d.ts +96 -4
  71. package/dist/wirings/ai-agent/index.d.ts +3 -1
  72. package/dist/wirings/ai-agent/index.js +2 -0
  73. package/dist/wirings/channel/channel-common.d.ts +2 -2
  74. package/dist/wirings/channel/channel-handler.d.ts +7 -4
  75. package/dist/wirings/channel/channel-handler.js +15 -5
  76. package/dist/wirings/channel/channel-middleware-runner.js +1 -0
  77. package/dist/wirings/channel/channel-runner.d.ts +5 -5
  78. package/dist/wirings/channel/channel-runner.js +3 -2
  79. package/dist/wirings/channel/channel-store.d.ts +1 -1
  80. package/dist/wirings/channel/channel.types.d.ts +10 -6
  81. package/dist/wirings/channel/index.d.ts +1 -1
  82. package/dist/wirings/channel/local/local-channel-handler.d.ts +7 -0
  83. package/dist/wirings/channel/local/local-channel-handler.js +17 -0
  84. package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
  85. package/dist/wirings/channel/local/local-channel-runner.js +18 -4
  86. package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
  87. package/dist/wirings/channel/log-channels.d.ts +1 -1
  88. package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +2 -1
  89. package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
  90. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
  91. package/dist/wirings/channel/serverless/serverless-channel-runner.js +26 -20
  92. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
  93. package/dist/wirings/cli/cli-runner.d.ts +2 -2
  94. package/dist/wirings/cli/cli-runner.js +3 -0
  95. package/dist/wirings/cli/cli.types.d.ts +3 -3
  96. package/dist/wirings/cli/command-parser.d.ts +1 -1
  97. package/dist/wirings/gateway/gateway-runner.d.ts +24 -0
  98. package/dist/wirings/gateway/gateway-runner.js +325 -0
  99. package/dist/wirings/gateway/gateway.types.d.ts +127 -0
  100. package/dist/wirings/gateway/index.d.ts +2 -0
  101. package/dist/wirings/gateway/index.js +1 -0
  102. package/dist/wirings/http/http-runner.d.ts +9 -9
  103. package/dist/wirings/http/http-runner.js +36 -14
  104. package/dist/wirings/http/http.types.d.ts +2 -6
  105. package/dist/wirings/http/log-http-routes.d.ts +1 -1
  106. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
  107. package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
  108. package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
  109. package/dist/wirings/http/routers/http-router.d.ts +1 -1
  110. package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
  111. package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
  112. package/dist/wirings/mcp/mcp-runner.d.ts +0 -3
  113. package/dist/wirings/mcp/mcp-runner.js +4 -2
  114. package/dist/wirings/mcp/mcp.types.d.ts +2 -2
  115. package/dist/wirings/oauth2/oauth2-client.d.ts +3 -3
  116. package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +1 -1
  117. package/dist/wirings/queue/index.d.ts +1 -1
  118. package/dist/wirings/queue/index.js +1 -1
  119. package/dist/wirings/queue/queue-runner.d.ts +1 -12
  120. package/dist/wirings/queue/queue-runner.js +4 -12
  121. package/dist/wirings/queue/queue.types.d.ts +3 -9
  122. package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
  123. package/dist/wirings/queue/register-queue-helper.js +1 -1
  124. package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
  125. package/dist/wirings/rpc/index.d.ts +2 -0
  126. package/dist/wirings/rpc/index.js +1 -0
  127. package/dist/wirings/rpc/rpc-runner.d.ts +36 -14
  128. package/dist/wirings/rpc/rpc-runner.js +56 -28
  129. package/dist/wirings/rpc/rpc-types.d.ts +14 -2
  130. package/dist/wirings/rpc/wire-addon.d.ts +10 -0
  131. package/dist/wirings/rpc/wire-addon.js +9 -0
  132. package/dist/wirings/scheduler/index.d.ts +1 -1
  133. package/dist/wirings/scheduler/index.js +1 -1
  134. package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
  135. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -10
  136. package/dist/wirings/scheduler/scheduler-runner.js +4 -25
  137. package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
  138. package/dist/wirings/trigger/pikku-trigger-service.d.ts +2 -6
  139. package/dist/wirings/trigger/pikku-trigger-service.js +11 -16
  140. package/dist/wirings/trigger/trigger-runner.d.ts +1 -5
  141. package/dist/wirings/trigger/trigger-runner.js +4 -3
  142. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -6
  143. package/dist/wirings/workflow/pikku-workflow-service.js +20 -29
  144. package/dist/wirings/workflow/workflow.types.d.ts +2 -2
  145. package/package.json +4 -2
  146. package/src/crypto-utils.test.ts +116 -0
  147. package/src/errors/error.test.ts +143 -2
  148. package/src/errors/errors.ts +10 -0
  149. package/src/errors/index.ts +1 -0
  150. package/src/function/function-runner.test.ts +2 -2
  151. package/src/function/function-runner.ts +72 -49
  152. package/src/function/functions.types.ts +1 -0
  153. package/src/handle-error.test.ts +361 -0
  154. package/src/handle-error.ts +4 -4
  155. package/src/index.ts +3 -10
  156. package/src/internal.ts +6 -0
  157. package/src/middleware/auth-apikey.test.ts +1 -1
  158. package/src/middleware/auth-bearer.test.ts +1 -1
  159. package/src/middleware/auth-bearer.ts +2 -5
  160. package/src/middleware/auth-cookie.test.ts +1 -1
  161. package/src/middleware/auth-cookie.ts +3 -5
  162. package/src/middleware/cors.test.ts +424 -0
  163. package/src/middleware/cors.ts +14 -6
  164. package/src/middleware/remote-auth.test.ts +488 -0
  165. package/src/middleware-runner.test.ts +1 -1
  166. package/src/middleware-runner.ts +2 -1
  167. package/src/permissions.test.ts +2 -2
  168. package/src/permissions.ts +3 -2
  169. package/src/pikku-state.test.ts +224 -0
  170. package/src/pikku-state.ts +45 -28
  171. package/src/schema.test.ts +198 -6
  172. package/src/schema.ts +11 -7
  173. package/src/services/ai-agent-runner-service.ts +15 -3
  174. package/src/services/ai-run-state-service.ts +1 -1
  175. package/src/services/ai-storage-service.ts +1 -1
  176. package/src/services/content-service.ts +7 -0
  177. package/src/services/gateway-service.ts +20 -0
  178. package/src/services/gopass-secrets.ts +4 -1
  179. package/src/services/in-memory-ai-run-state-service.ts +73 -0
  180. package/src/services/in-memory-trigger-service.ts +6 -10
  181. package/src/services/in-memory-workflow-service.test.ts +351 -0
  182. package/src/services/index.ts +4 -1
  183. package/src/services/local-content.ts +9 -3
  184. package/src/services/local-gateway-service.ts +62 -0
  185. package/src/services/local-secrets.test.ts +80 -0
  186. package/src/services/local-secrets.ts +2 -2
  187. package/src/services/local-variables.test.ts +61 -0
  188. package/src/services/local-variables.ts +1 -1
  189. package/src/services/logger-console.test.ts +118 -0
  190. package/src/services/logger-console.ts +2 -1
  191. package/src/services/scheduler-service.ts +0 -18
  192. package/src/services/scoped-secret-service.test.ts +74 -0
  193. package/src/services/scoped-secret-service.ts +1 -1
  194. package/src/services/trigger-service.ts +0 -21
  195. package/src/services/typed-secret-service.test.ts +93 -0
  196. package/src/services/typed-variables-service.test.ts +73 -0
  197. package/src/services/user-session-service.test.ts +113 -0
  198. package/src/services/user-session-service.ts +3 -3
  199. package/src/services/workflow-service.ts +2 -12
  200. package/src/time-utils.test.ts +1 -1
  201. package/src/types/core.types.ts +28 -19
  202. package/src/types/state.types.ts +32 -15
  203. package/src/utils.test.ts +350 -0
  204. package/src/utils.ts +14 -13
  205. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
  206. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +238 -0
  207. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
  208. package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
  209. package/src/wirings/ai-agent/ai-agent-memory.ts +10 -1
  210. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
  211. package/src/wirings/ai-agent/ai-agent-prepare.ts +98 -46
  212. package/src/wirings/ai-agent/ai-agent-registry.ts +1 -1
  213. package/src/wirings/ai-agent/ai-agent-runner.test.ts +245 -3
  214. package/src/wirings/ai-agent/ai-agent-runner.ts +121 -7
  215. package/src/wirings/ai-agent/ai-agent-stream.test.ts +430 -24
  216. package/src/wirings/ai-agent/ai-agent-stream.ts +390 -104
  217. package/src/wirings/ai-agent/ai-agent.types.ts +91 -4
  218. package/src/wirings/ai-agent/index.ts +13 -0
  219. package/src/wirings/channel/channel-common.ts +2 -2
  220. package/src/wirings/channel/channel-handler.ts +43 -11
  221. package/src/wirings/channel/channel-middleware-runner.ts +1 -0
  222. package/src/wirings/channel/channel-runner.ts +6 -6
  223. package/src/wirings/channel/channel-store.ts +1 -1
  224. package/src/wirings/channel/channel.types.ts +15 -8
  225. package/src/wirings/channel/index.ts +1 -0
  226. package/src/wirings/channel/local/local-channel-handler.ts +26 -0
  227. package/src/wirings/channel/local/local-channel-runner.test.ts +19 -12
  228. package/src/wirings/channel/local/local-channel-runner.ts +33 -14
  229. package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
  230. package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
  231. package/src/wirings/channel/log-channels.ts +1 -1
  232. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +2 -0
  233. package/src/wirings/channel/pikku-abstract-channel-handler.ts +8 -1
  234. package/src/wirings/channel/serverless/serverless-channel-runner.ts +38 -33
  235. package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
  236. package/src/wirings/cli/cli-runner.test.ts +1 -1
  237. package/src/wirings/cli/cli-runner.ts +14 -4
  238. package/src/wirings/cli/cli.types.ts +3 -3
  239. package/src/wirings/cli/command-parser.test.ts +1 -1
  240. package/src/wirings/cli/command-parser.ts +1 -1
  241. package/src/wirings/gateway/gateway-runner.test.ts +474 -0
  242. package/src/wirings/gateway/gateway-runner.ts +411 -0
  243. package/src/wirings/gateway/gateway.types.ts +149 -0
  244. package/src/wirings/gateway/index.ts +13 -0
  245. package/src/wirings/http/http-routes.test.ts +1 -1
  246. package/src/wirings/http/http-runner.test.ts +9 -17
  247. package/src/wirings/http/http-runner.ts +46 -27
  248. package/src/wirings/http/http.types.ts +1 -14
  249. package/src/wirings/http/log-http-routes.ts +1 -1
  250. package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
  251. package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
  252. package/src/wirings/http/routers/http-router.ts +1 -1
  253. package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
  254. package/src/wirings/http/routers/path-to-regex.ts +4 -3
  255. package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
  256. package/src/wirings/mcp/mcp-runner.ts +9 -15
  257. package/src/wirings/mcp/mcp.types.ts +2 -2
  258. package/src/wirings/oauth2/oauth2-client.ts +3 -3
  259. package/src/wirings/oauth2/wire-oauth2-credential.ts +1 -1
  260. package/src/wirings/queue/index.ts +0 -1
  261. package/src/wirings/queue/queue-runner.test.ts +52 -25
  262. package/src/wirings/queue/queue-runner.ts +8 -30
  263. package/src/wirings/queue/queue.types.ts +3 -13
  264. package/src/wirings/queue/register-queue-helper.ts +3 -5
  265. package/src/wirings/queue/validate-worker-config.test.ts +108 -0
  266. package/src/wirings/queue/validate-worker-config.ts +4 -1
  267. package/src/wirings/rpc/index.ts +2 -0
  268. package/src/wirings/rpc/rpc-runner.ts +92 -49
  269. package/src/wirings/rpc/rpc-types.ts +17 -2
  270. package/src/wirings/rpc/wire-addon.ts +20 -0
  271. package/src/wirings/scheduler/index.ts +0 -1
  272. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  273. package/src/wirings/scheduler/scheduler-runner.test.ts +49 -60
  274. package/src/wirings/scheduler/scheduler-runner.ts +9 -56
  275. package/src/wirings/scheduler/scheduler.types.ts +2 -2
  276. package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
  277. package/src/wirings/trigger/pikku-trigger-service.ts +17 -39
  278. package/src/wirings/trigger/trigger-runner.test.ts +79 -0
  279. package/src/wirings/trigger/trigger-runner.ts +8 -11
  280. package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
  281. package/src/wirings/workflow/graph/graph-runner.test.ts +14 -22
  282. package/src/wirings/workflow/graph/template.test.ts +49 -0
  283. package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -27
  284. package/src/wirings/workflow/pikku-workflow-service.ts +29 -45
  285. package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
  286. package/src/wirings/workflow/workflow.types.ts +2 -2
  287. package/tsconfig.tsbuildinfo +1 -1
  288. package/src/wirings/workflow/workflow-utils.ts +0 -0
  289. /package/dist/{wirings/workflow/workflow-utils.d.ts → services/gateway-service.js} +0 -0
  290. /package/dist/wirings/{workflow/workflow-utils.js → gateway/gateway.types.js} +0 -0
@@ -0,0 +1,325 @@
1
+ import { pikkuState } from '../../pikku-state.js';
2
+ import { addFunction } from '../../function/function-runner.js';
3
+ import { runMiddleware } from '../../middleware-runner.js';
4
+ import { httpRouter } from '../http/routers/http-router.js';
5
+ /**
6
+ * Register a messaging gateway.
7
+ *
8
+ * `wireGateway` is a meta-wiring that composes existing primitives
9
+ * (`wireHTTP`, `wireChannel`) under the hood. It does not replace them;
10
+ * it layers on top.
11
+ *
12
+ * @param config - Gateway configuration (name, type, adapter, func, middleware, etc.)
13
+ */
14
+ export const wireGateway = (config) => {
15
+ // Store gateway config
16
+ pikkuState(null, 'gateway', 'gateways').set(config.name, config);
17
+ switch (config.type) {
18
+ case 'webhook':
19
+ wireWebhookGateway(config);
20
+ break;
21
+ case 'websocket':
22
+ wireWebsocketGateway(config);
23
+ break;
24
+ case 'listener':
25
+ wireListenerGateway(config);
26
+ break;
27
+ default:
28
+ throw new Error(`Unknown gateway type '${config.type}' for gateway '${config.name}'`);
29
+ }
30
+ };
31
+ // ---------------------------------------------------------------------------
32
+ // Webhook gateway — platform POSTs to us
33
+ // ---------------------------------------------------------------------------
34
+ const wireWebhookGateway = (config) => {
35
+ const { name, route, adapter } = config;
36
+ if (!route) {
37
+ throw new Error(`Webhook gateway '${name}' requires a route`);
38
+ }
39
+ const postFuncId = `gateway__${name}__post`;
40
+ const httpMeta = pikkuState(null, 'http', 'meta');
41
+ const funcMeta = pikkuState(null, 'function', 'meta');
42
+ const routes = pikkuState(null, 'http', 'routes');
43
+ // --- POST handler (main message receiver) --------------------------------
44
+ funcMeta[postFuncId] = {
45
+ pikkuFuncId: postFuncId,
46
+ inputSchemaName: null,
47
+ outputSchemaName: null,
48
+ sessionless: true,
49
+ };
50
+ httpMeta['post'][route] = {
51
+ pikkuFuncId: postFuncId,
52
+ route,
53
+ method: 'post',
54
+ };
55
+ const postHandler = {
56
+ auth: false,
57
+ func: createWebhookPostHandler(config),
58
+ };
59
+ addFunction(postFuncId, postHandler);
60
+ if (!routes.has('post')) {
61
+ routes.set('post', new Map());
62
+ }
63
+ routes.get('post').set(route, {
64
+ method: 'post',
65
+ route,
66
+ func: postHandler,
67
+ auth: false,
68
+ });
69
+ // --- GET handler (webhook verification, e.g. WhatsApp challenge) ---------
70
+ if (adapter.verifyWebhook) {
71
+ const verifyFuncId = `gateway__${name}__verify`;
72
+ funcMeta[verifyFuncId] = {
73
+ pikkuFuncId: verifyFuncId,
74
+ inputSchemaName: null,
75
+ outputSchemaName: null,
76
+ sessionless: true,
77
+ };
78
+ httpMeta['get'][route] = {
79
+ pikkuFuncId: verifyFuncId,
80
+ route,
81
+ method: 'get',
82
+ };
83
+ const verifyHandler = {
84
+ auth: false,
85
+ func: createWebhookVerifyHandler(adapter),
86
+ };
87
+ addFunction(verifyFuncId, verifyHandler);
88
+ if (!routes.has('get')) {
89
+ routes.set('get', new Map());
90
+ }
91
+ routes.get('get').set(route, {
92
+ method: 'get',
93
+ route,
94
+ func: verifyHandler,
95
+ auth: false,
96
+ });
97
+ }
98
+ // Force router to re-initialize on next match
99
+ httpRouter.reset();
100
+ };
101
+ /**
102
+ * Creates the POST handler function for a webhook gateway.
103
+ *
104
+ * Flow:
105
+ * 1. Check for POST-based verification (e.g. Slack `url_verification`)
106
+ * 2. Parse body via adapter → GatewayInboundMessage (or null to ignore)
107
+ * 3. Populate `wire.gateway`
108
+ * 4. Run user middleware (which can read `wire.gateway` for auth)
109
+ * 5. Call user func with parsed message
110
+ * 6. Auto-send response via adapter if func returns outbound content
111
+ */
112
+ const createWebhookPostHandler = (config) => {
113
+ const { name, adapter, func: userFunc, middleware: userMiddleware } = config;
114
+ const userFuncConfig = userFunc;
115
+ return async (services, data, wire) => {
116
+ // Check for POST-based webhook verification (e.g. Slack url_verification)
117
+ if (adapter.verifyWebhook) {
118
+ const verifyResult = await adapter.verifyWebhook(data, wire.http?.request);
119
+ if (verifyResult.verified) {
120
+ return verifyResult.response;
121
+ }
122
+ }
123
+ // Parse the platform-specific payload
124
+ const parsed = adapter.parse(data);
125
+ if (!parsed) {
126
+ // Ignored event (delivery receipt, typing indicator, etc.)
127
+ return { ok: true };
128
+ }
129
+ // Populate wire.gateway
130
+ const gateway = {
131
+ gatewayName: name,
132
+ senderId: parsed.senderId,
133
+ platform: adapter.name,
134
+ send: (msg) => adapter.send(parsed.senderId, msg),
135
+ };
136
+ wire.gateway = gateway;
137
+ // Build combined middleware chain: gateway-level + func-level
138
+ const allMiddleware = [
139
+ ...(userMiddleware || []),
140
+ ...(userFuncConfig.middleware || []),
141
+ ];
142
+ const exec = async () => {
143
+ const result = await userFuncConfig.func(services, parsed, wire);
144
+ // Auto-send response if the func returns outbound content
145
+ if (result && (result.text || result.richContent || result.attachments)) {
146
+ await adapter.send(parsed.senderId, result);
147
+ }
148
+ return { ok: true };
149
+ };
150
+ if (allMiddleware.length > 0) {
151
+ return await runMiddleware(services, wire, allMiddleware, exec);
152
+ }
153
+ return await exec();
154
+ };
155
+ };
156
+ /**
157
+ * Creates the GET handler for webhook verification challenges.
158
+ * Passes query parameters to the adapter's verifyWebhook method.
159
+ */
160
+ const createWebhookVerifyHandler = (adapter) => {
161
+ return async (_services, _data, wire) => {
162
+ if (!adapter.verifyWebhook) {
163
+ return { error: 'Verification not supported' };
164
+ }
165
+ const query = wire.http?.request?.query();
166
+ const result = await adapter.verifyWebhook(query, wire.http?.request);
167
+ if (result.verified) {
168
+ return result.response;
169
+ }
170
+ return { error: 'Verification failed' };
171
+ };
172
+ };
173
+ // ---------------------------------------------------------------------------
174
+ // WebSocket gateway — client connects via WebSocket
175
+ // ---------------------------------------------------------------------------
176
+ const wireWebsocketGateway = (config) => {
177
+ const { name, route, adapter } = config;
178
+ if (!route) {
179
+ throw new Error(`WebSocket gateway '${name}' requires a route`);
180
+ }
181
+ // Store gateway config — the channel runner will reference this
182
+ pikkuState(null, 'gateway', 'gateways').set(config.name, config);
183
+ const channelsMeta = pikkuState(null, 'channel', 'meta');
184
+ const channels = pikkuState(null, 'channel', 'channels');
185
+ const messageFuncId = `gateway__${name}__message`;
186
+ const connectFuncId = `gateway__${name}__connect`;
187
+ // Add function metadata
188
+ const funcMeta = pikkuState(null, 'function', 'meta');
189
+ funcMeta[messageFuncId] = {
190
+ pikkuFuncId: messageFuncId,
191
+ inputSchemaName: null,
192
+ outputSchemaName: null,
193
+ sessionless: true,
194
+ };
195
+ funcMeta[connectFuncId] = {
196
+ pikkuFuncId: connectFuncId,
197
+ inputSchemaName: null,
198
+ outputSchemaName: null,
199
+ sessionless: true,
200
+ };
201
+ // Add channel metadata
202
+ channelsMeta[name] = {
203
+ name,
204
+ route,
205
+ gateway: true,
206
+ connect: { pikkuFuncId: connectFuncId },
207
+ message: { pikkuFuncId: messageFuncId },
208
+ };
209
+ const userFuncConfig = config.func;
210
+ const userMiddleware = config.middleware;
211
+ // Register onConnect
212
+ addFunction(connectFuncId, {
213
+ auth: false,
214
+ func: async (_services, _data, wire) => {
215
+ ;
216
+ wire.gateway = {
217
+ gatewayName: name,
218
+ senderId: '',
219
+ platform: adapter.name,
220
+ send: async (msg) => {
221
+ wire.channel?.send(msg);
222
+ },
223
+ };
224
+ },
225
+ });
226
+ // Register onMessage
227
+ addFunction(messageFuncId, {
228
+ auth: false,
229
+ func: async (services, data, wire) => {
230
+ const parsed = adapter.parse(data);
231
+ if (!parsed)
232
+ return;
233
+ const gateway = {
234
+ gatewayName: name,
235
+ senderId: parsed.senderId,
236
+ platform: adapter.name,
237
+ send: async (msg) => {
238
+ wire.channel?.send(msg);
239
+ },
240
+ };
241
+ wire.gateway = gateway;
242
+ const allMiddleware = [
243
+ ...(userMiddleware || []),
244
+ ...(userFuncConfig.middleware || []),
245
+ ];
246
+ const exec = async () => {
247
+ const result = await userFuncConfig.func(services, parsed, wire);
248
+ if (result &&
249
+ (result.text || result.richContent || result.attachments)) {
250
+ wire.channel?.send(result);
251
+ }
252
+ };
253
+ if (allMiddleware.length > 0) {
254
+ await runMiddleware(services, wire, allMiddleware, exec);
255
+ }
256
+ else {
257
+ await exec();
258
+ }
259
+ },
260
+ });
261
+ // Store channel config
262
+ channels.set(name, {
263
+ name,
264
+ route,
265
+ auth: false,
266
+ onConnect: { func: async () => { } },
267
+ onMessage: { func: async () => { } },
268
+ });
269
+ // Force router to re-initialize
270
+ httpRouter.reset();
271
+ };
272
+ // ---------------------------------------------------------------------------
273
+ // Listener gateway — standalone event loop, no route
274
+ // ---------------------------------------------------------------------------
275
+ const wireListenerGateway = (config) => {
276
+ // Listener gateways don't register routes.
277
+ // They are started manually and call into the gateway's func directly.
278
+ // The gateway config is already stored in pikkuState.
279
+ pikkuState(null, 'gateway', 'gateways').set(config.name, config);
280
+ };
281
+ /**
282
+ * Create the message handler callback for a listener gateway.
283
+ *
284
+ * Returns a function `(rawData: unknown) => Promise<void>` that can be
285
+ * passed to `adapter.init()`. Used by `LocalGatewayService` (and any
286
+ * other GatewayService implementation) to wire up listener gateways.
287
+ *
288
+ * @param name - Gateway name (for wire.gateway metadata)
289
+ * @param config - The gateway configuration (adapter, func, middleware)
290
+ * @param singletonServices - Singleton services to pass to handler/middleware
291
+ */
292
+ export const createListenerMessageHandler = (name, config, singletonServices) => {
293
+ const { adapter } = config;
294
+ const userFuncConfig = config.func;
295
+ const userMiddleware = config.middleware;
296
+ return async (rawData) => {
297
+ const parsed = adapter.parse(rawData);
298
+ if (!parsed)
299
+ return;
300
+ const wire = {};
301
+ const gateway = {
302
+ gatewayName: name,
303
+ senderId: parsed.senderId,
304
+ platform: adapter.name,
305
+ send: (msg) => adapter.send(parsed.senderId, msg),
306
+ };
307
+ wire.gateway = gateway;
308
+ const allMiddleware = [
309
+ ...(userMiddleware || []),
310
+ ...(userFuncConfig.middleware || []),
311
+ ];
312
+ const exec = async () => {
313
+ const result = await userFuncConfig.func(singletonServices, parsed, wire);
314
+ if (result && (result.text || result.richContent || result.attachments)) {
315
+ await adapter.send(parsed.senderId, result);
316
+ }
317
+ };
318
+ if (allMiddleware.length > 0) {
319
+ await runMiddleware(singletonServices, wire, allMiddleware, exec);
320
+ }
321
+ else {
322
+ await exec();
323
+ }
324
+ };
325
+ };
@@ -0,0 +1,127 @@
1
+ import type { CommonWireMeta, CorePikkuMiddleware, CorePikkuMiddlewareGroup } from '../../types/core.types.js';
2
+ import type { CorePikkuFunctionConfig, CorePermissionGroup, CorePikkuPermission } from '../../function/functions.types.js';
3
+ import type { PikkuHTTPRequest } from '../http/http.types.js';
4
+ /**
5
+ * Attachment in gateway messages (images, files, etc.)
6
+ */
7
+ export interface GatewayAttachment {
8
+ type: string;
9
+ url?: string;
10
+ data?: ArrayBuffer | Uint8Array;
11
+ mimeType?: string;
12
+ filename?: string;
13
+ }
14
+ /**
15
+ * Normalized inbound message from any platform
16
+ */
17
+ export interface GatewayInboundMessage {
18
+ /** Platform-specific sender identifier (phone number, Slack user ID, etc.) */
19
+ senderId: string;
20
+ /** Message text content */
21
+ text: string;
22
+ /** Original platform-specific payload */
23
+ raw: unknown;
24
+ /** Optional file/media attachments */
25
+ attachments?: GatewayAttachment[];
26
+ /** Optional platform-specific metadata */
27
+ metadata?: Record<string, unknown>;
28
+ }
29
+ /**
30
+ * Outbound message to send back via the platform
31
+ */
32
+ export interface GatewayOutboundMessage {
33
+ /** Plain text response */
34
+ text?: string;
35
+ /** Platform-specific rich content (Slack blocks, WhatsApp templates, etc.) */
36
+ richContent?: Record<string, unknown>;
37
+ /** Optional file/media attachments */
38
+ attachments?: GatewayAttachment[];
39
+ }
40
+ /**
41
+ * Result of webhook verification (e.g., WhatsApp GET challenge, Slack url_verification)
42
+ */
43
+ export type WebhookVerificationResult = {
44
+ verified: true;
45
+ response: unknown;
46
+ } | {
47
+ verified: false;
48
+ };
49
+ /**
50
+ * Gateway adapter interface — implemented by platform-specific addon packages.
51
+ *
52
+ * Two responsibilities:
53
+ * 1. Parse incoming platform-specific format into normalized GatewayInboundMessage
54
+ * 2. Send outgoing GatewayOutboundMessage via the platform's API
55
+ */
56
+ export interface GatewayAdapter {
57
+ /** Platform name (e.g., 'whatsapp', 'slack', 'telegram') */
58
+ name: string;
59
+ /** Parse platform-specific payload into normalized message. Return null to ignore (e.g., delivery receipts). */
60
+ parse(data: unknown): GatewayInboundMessage | null;
61
+ /** Send a message to a specific sender via the platform's API */
62
+ send(senderId: string, message: GatewayOutboundMessage): Promise<void>;
63
+ /** Initialize the adapter (connect to platform, start listening).
64
+ * Called by GatewayService.start() — the adapter should call onMessage for each incoming event. */
65
+ init(onMessage: (data: unknown) => Promise<void>): Promise<void>;
66
+ /** Tear down the adapter (disconnect, release resources). */
67
+ close(): Promise<void>;
68
+ /** Handle webhook verification challenges (only for webhook type).
69
+ * Receives the data (body or query params) and the Pikku HTTP request for additional inspection. */
70
+ verifyWebhook?(data: unknown, request?: PikkuHTTPRequest): WebhookVerificationResult | Promise<WebhookVerificationResult>;
71
+ }
72
+ /**
73
+ * The gateway wire object available on wire.gateway inside handler functions and middleware
74
+ */
75
+ export interface PikkuGateway {
76
+ /** Name of this gateway instance */
77
+ gatewayName: string;
78
+ /** Platform-specific sender identifier */
79
+ senderId: string;
80
+ /** Platform name from adapter.name */
81
+ platform: string;
82
+ /** Send a proactive message to the sender */
83
+ send(msg: GatewayOutboundMessage): Promise<void>;
84
+ }
85
+ /**
86
+ * Gateway transport type:
87
+ * - 'webhook': Platform POSTs to us (WhatsApp Cloud API, Slack Events API, Telegram webhooks)
88
+ * - 'websocket': Client connects via WebSocket (WebChat, browser widget)
89
+ * - 'listener': Standalone event loop, no route (Baileys, Signal CLI, Matrix sync)
90
+ */
91
+ export type GatewayTransportType = 'webhook' | 'websocket' | 'listener';
92
+ /**
93
+ * Core gateway configuration for wireGateway()
94
+ */
95
+ export type CoreGateway<PikkuFunctionConfig = CorePikkuFunctionConfig<any, any>, PikkuPermission extends CorePikkuPermission = CorePikkuPermission, PikkuMiddleware extends CorePikkuMiddleware = CorePikkuMiddleware> = {
96
+ /** Unique name for this gateway */
97
+ name: string;
98
+ /** Transport type */
99
+ type: GatewayTransportType;
100
+ /** HTTP route for webhook/websocket types */
101
+ route?: string;
102
+ /** The gateway adapter (parse inbound, send outbound) */
103
+ adapter: GatewayAdapter;
104
+ /** The handler function that processes parsed messages */
105
+ func: PikkuFunctionConfig;
106
+ /** Optional middleware chain (e.g., auth) */
107
+ middleware?: CorePikkuMiddlewareGroup<any, any>;
108
+ /** Optional permissions */
109
+ permissions?: CorePermissionGroup | PikkuPermission[];
110
+ /** Optional tags for categorization */
111
+ tags?: string[];
112
+ /** Whether authentication is required (default: true) */
113
+ auth?: boolean;
114
+ };
115
+ /**
116
+ * Metadata for a registered gateway, stored in state
117
+ */
118
+ export type GatewayMeta = CommonWireMeta & {
119
+ name: string;
120
+ type: GatewayTransportType;
121
+ route?: string;
122
+ gateway: true;
123
+ };
124
+ /**
125
+ * All gateway metadata keyed by name
126
+ */
127
+ export type GatewaysMeta = Record<string, GatewayMeta>;
@@ -0,0 +1,2 @@
1
+ export { wireGateway, createListenerMessageHandler } from './gateway-runner.js';
2
+ export type { GatewayAdapter, GatewayAttachment, GatewayInboundMessage, GatewayOutboundMessage, GatewayMeta, GatewaysMeta, GatewayTransportType, CoreGateway, PikkuGateway, WebhookVerificationResult, } from './gateway.types.js';
@@ -0,0 +1 @@
1
+ export { wireGateway, createListenerMessageHandler } from './gateway-runner.js';
@@ -1,6 +1,6 @@
1
- import { CoreHTTPFunctionWiring, RunHTTPWiringOptions, RunHTTPWiringParams, PikkuHTTP, PikkuHTTPRequest, PikkuHTTPResponse } from './http.types.js';
2
- import { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission, CorePermissionGroup } from '../../function/functions.types.js';
3
- import { CorePikkuMiddleware, CorePikkuMiddlewareGroup } from '../../types/core.types.js';
1
+ import type { CoreHTTPFunctionWiring, RunHTTPWiringOptions, PikkuHTTP, PikkuHTTPRequest, PikkuHTTPResponse } from './http.types.js';
2
+ import type { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission, CorePermissionGroup } from '../../function/functions.types.js';
3
+ import type { CorePikkuMiddleware, CorePikkuMiddlewareGroup } from '../../types/core.types.js';
4
4
  import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
5
5
  /**
6
6
  * Registers HTTP middleware for a specific route pattern.
@@ -101,10 +101,10 @@ export declare const createHTTPWire: (request: PikkuHTTPRequest | undefined, res
101
101
  * @template In Expected input data type.
102
102
  * @template Out Expected output data type.
103
103
  * @param {Request} request - The native Fetch API Request object.
104
- * @param {RunHTTPWiringOptions & RunHTTPWiringParams} params - Additional options including services and session management.
104
+ * @param {RunHTTPWiringOptions} params - Additional options including services and session management.
105
105
  * @returns {Promise<Response>} A promise that resolves to a Fetch API Response object.
106
106
  */
107
- export declare const fetch: <In, Out>(request: Request, params: RunHTTPWiringOptions & RunHTTPWiringParams) => Promise<Response>;
107
+ export declare const fetch: <In, Out>(request: Request, params?: RunHTTPWiringOptions) => Promise<Response>;
108
108
  /**
109
109
  * Executes an HTTP route using a Pikku-specific request wrapper.
110
110
  *
@@ -114,10 +114,10 @@ export declare const fetch: <In, Out>(request: Request, params: RunHTTPWiringOpt
114
114
  * @template In Expected input data type.
115
115
  * @template Out Expected output data type.
116
116
  * @param {Request | PikkuHTTPRequest} request - The request object.
117
- * @param {RunHTTPWiringOptions & RunHTTPWiringParams} params - Execution options including services and session configuration.
117
+ * @param {RunHTTPWiringOptions} params - Execution options including services and session configuration.
118
118
  * @returns {Promise<PikkuFetchHTTPResponse>} A promise that resolves to a PikkuFetchHTTPResponse object.
119
119
  */
120
- export declare const pikkuFetch: <In, Out>(request: Request | PikkuHTTPRequest, params: RunHTTPWiringOptions & RunHTTPWiringParams) => Promise<PikkuFetchHTTPResponse>;
120
+ export declare const pikkuFetch: <In, Out>(request: Request | PikkuHTTPRequest, params?: RunHTTPWiringOptions) => Promise<PikkuFetchHTTPResponse>;
121
121
  /**
122
122
  * Core function to process an HTTP request through route matching, validation,
123
123
  * middleware execution, error handling, and session service cleanup.
@@ -133,7 +133,7 @@ export declare const pikkuFetch: <In, Out>(request: Request | PikkuHTTPRequest,
133
133
  * @template Out Expected output data type.
134
134
  * @param {Request | PikkuHTTPRequest} request - The incoming HTTP request.
135
135
  * @param {PikkuHTTPResponse} response - The response object to be populated.
136
- * @param {RunHTTPWiringOptions & RunHTTPWiringParams} options - Options such as singleton services, session handling, and error configuration.
136
+ * @param {RunHTTPWiringOptions} options - Options such as singleton services, session handling, and error configuration.
137
137
  * @returns {Promise<Out | void>} The output from the route handler or void if an error occurred.
138
138
  */
139
- export declare const fetchData: <In, Out>(request: Request | PikkuHTTPRequest, response: PikkuHTTPResponse, { singletonServices, createWireServices, skipUserSession, respondWith404, logWarningsForStatusCodes, coerceDataFromSchema, bubbleErrors, generateRequestId, }: RunHTTPWiringOptions & RunHTTPWiringParams) => Promise<Out | void>;
139
+ export declare const fetchData: <In, Out>(request: Request | PikkuHTTPRequest, response: PikkuHTTPResponse, { skipUserSession, respondWith404, logWarningsForStatusCodes, coerceDataFromSchema, bubbleErrors, generateRequestId, }?: RunHTTPWiringOptions) => Promise<Out | void>;
@@ -1,6 +1,7 @@
1
1
  import { NotFoundError, PikkuMissingMetaError } from '../../errors/errors.js';
2
2
  import { closeWireServices, createWeakUID, isSerializable, } from '../../utils.js';
3
- import { PikkuSessionService, createMiddlewareSessionWireProps, } from '../../services/user-session-service.js';
3
+ import { getSingletonServices, getCreateWireServices, } from '../../pikku-state.js';
4
+ import { PikkuSessionService } from '../../services/user-session-service.js';
4
5
  import { handleHTTPError } from '../../handle-error.js';
5
6
  import { pikkuState } from '../../pikku-state.js';
6
7
  import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
@@ -8,6 +9,7 @@ import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js';
8
9
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
9
10
  import { httpRouter } from './routers/http-router.js';
10
11
  import { validateSchema } from '../../schema.js';
12
+ import { runMiddleware } from '../../middleware-runner.js';
11
13
  /**
12
14
  * Extract headers from a PikkuHTTPRequest based on the schema keys
13
15
  */
@@ -238,6 +240,9 @@ const executeRoute = async (services, matchedRoute, http, options) => {
238
240
  send: (data) => {
239
241
  response.arrayBuffer(isSerializable(data) ? JSON.stringify(data) : data);
240
242
  },
243
+ sendBinary: (data) => {
244
+ response.arrayBuffer(data);
245
+ },
241
246
  close: () => {
242
247
  channel.state = 'closed';
243
248
  response.close?.();
@@ -248,7 +253,10 @@ const executeRoute = async (services, matchedRoute, http, options) => {
248
253
  const wire = {
249
254
  http,
250
255
  channel,
251
- ...createMiddlewareSessionWireProps(userSession),
256
+ session: userSession.get(),
257
+ setSession: (s) => userSession.setInitial(s),
258
+ getSession: () => userSession.get(),
259
+ hasSessionChanged: () => userSession.sessionChanged,
252
260
  };
253
261
  result = await runPikkuFunc('http', `${meta.method}:${meta.route}`, meta.pikkuFuncId, {
254
262
  singletonServices,
@@ -290,10 +298,10 @@ const executeRoute = async (services, matchedRoute, http, options) => {
290
298
  * @template In Expected input data type.
291
299
  * @template Out Expected output data type.
292
300
  * @param {Request} request - The native Fetch API Request object.
293
- * @param {RunHTTPWiringOptions & RunHTTPWiringParams} params - Additional options including services and session management.
301
+ * @param {RunHTTPWiringOptions} params - Additional options including services and session management.
294
302
  * @returns {Promise<Response>} A promise that resolves to a Fetch API Response object.
295
303
  */
296
- export const fetch = async (request, params) => {
304
+ export const fetch = async (request, params = {}) => {
297
305
  const pikkuResponse = new PikkuFetchHTTPResponse();
298
306
  await fetchData(request, pikkuResponse, params);
299
307
  return pikkuResponse.toResponse();
@@ -307,10 +315,10 @@ export const fetch = async (request, params) => {
307
315
  * @template In Expected input data type.
308
316
  * @template Out Expected output data type.
309
317
  * @param {Request | PikkuHTTPRequest} request - The request object.
310
- * @param {RunHTTPWiringOptions & RunHTTPWiringParams} params - Execution options including services and session configuration.
318
+ * @param {RunHTTPWiringOptions} params - Execution options including services and session configuration.
311
319
  * @returns {Promise<PikkuFetchHTTPResponse>} A promise that resolves to a PikkuFetchHTTPResponse object.
312
320
  */
313
- export const pikkuFetch = async (request, params) => {
321
+ export const pikkuFetch = async (request, params = {}) => {
314
322
  const pikkuResponse = new PikkuFetchHTTPResponse();
315
323
  await fetchData(request, pikkuResponse, params);
316
324
  return pikkuResponse;
@@ -330,24 +338,39 @@ export const pikkuFetch = async (request, params) => {
330
338
  * @template Out Expected output data type.
331
339
  * @param {Request | PikkuHTTPRequest} request - The incoming HTTP request.
332
340
  * @param {PikkuHTTPResponse} response - The response object to be populated.
333
- * @param {RunHTTPWiringOptions & RunHTTPWiringParams} options - Options such as singleton services, session handling, and error configuration.
341
+ * @param {RunHTTPWiringOptions} options - Options such as singleton services, session handling, and error configuration.
334
342
  * @returns {Promise<Out | void>} The output from the route handler or void if an error occurred.
335
343
  */
336
- export const fetchData = async (request, response, { singletonServices, createWireServices, skipUserSession = false, respondWith404 = true, logWarningsForStatusCodes = [], coerceDataFromSchema = true, bubbleErrors = false, generateRequestId, }) => {
337
- const requestId = request.getHeader?.('x-request-id') ||
338
- generateRequestId?.() ||
339
- createWeakUID();
344
+ export const fetchData = async (request, response, { skipUserSession = false, respondWith404 = true, logWarningsForStatusCodes = [], coerceDataFromSchema = true, bubbleErrors = false, generateRequestId, } = {}) => {
345
+ const singletonServices = getSingletonServices();
346
+ const createWireServices = getCreateWireServices();
340
347
  let wireServices;
341
348
  let result;
342
349
  // Combine the request and response into one wire object
343
- const http = createHTTPWire(request instanceof Request ? new PikkuFetchHTTPRequest(request) : request, response);
350
+ const pikkuRequest = request instanceof Request ? new PikkuFetchHTTPRequest(request) : request;
351
+ let requestId = null;
352
+ try {
353
+ requestId = pikkuRequest.header('x-request-id');
354
+ }
355
+ catch { }
356
+ requestId = requestId || generateRequestId?.() || createWeakUID();
357
+ const http = createHTTPWire(pikkuRequest, response);
344
358
  const apiType = http.request.method();
345
359
  const apiRoute = http.request.path();
346
360
  // Locate the matching route based on the HTTP method and path
347
361
  const matchedRoute = getMatchingRoute(apiType, apiRoute);
348
362
  try {
349
- // If no route matches, log the occurrence and throw a NotFoundError
350
363
  if (!matchedRoute) {
364
+ if (apiType.toLowerCase() === 'options') {
365
+ const httpGroups = pikkuState(null, 'middleware', 'httpGroup');
366
+ const globalMiddleware = httpGroups['*'];
367
+ const wire = { http: http };
368
+ if (globalMiddleware) {
369
+ await runMiddleware(singletonServices, wire, globalMiddleware);
370
+ }
371
+ response.status(204).json(undefined);
372
+ return;
373
+ }
351
374
  singletonServices.logger.info({
352
375
  message: 'Route not found',
353
376
  apiRoute,
@@ -366,7 +389,6 @@ export const fetchData = async (request, response, { singletonServices, createWi
366
389
  return result;
367
390
  }
368
391
  catch (e) {
369
- // Handle errors and, depending on configuration, bubble them up or respond with an error
370
392
  handleHTTPError(e, http, requestId, singletonServices.logger, logWarningsForStatusCodes, respondWith404, bubbleErrors);
371
393
  }
372
394
  finally {
@@ -1,7 +1,7 @@
1
1
  import type { SerializeOptions } from 'cookie';
2
2
  import type { StandardSchemaV1 } from '@standard-schema/spec';
3
- import { PikkuError } from '../../errors/error-handler.js';
4
- import type { CoreServices, CoreSingletonServices, CoreUserSession, CreateWireServices, CorePikkuMiddleware, CommonWireMeta } from '../../types/core.types.js';
3
+ import type { PikkuError } from '../../errors/error-handler.js';
4
+ import type { CorePikkuMiddleware, CommonWireMeta } from '../../types/core.types.js';
5
5
  import type { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission, CorePermissionGroup, CorePikkuFunctionConfig } from '../../function/functions.types.js';
6
6
  type ExtractHTTPWiringParams<S extends string> = S extends `${string}:${infer Param}/${infer Rest}` ? Param | ExtractHTTPWiringParams<`/${Rest}`> : S extends `${string}:${infer Param}` ? Param : never;
7
7
  export type AssertHTTPWiringParams<In, HTTPWiring extends string> = ExtractHTTPWiringParams<HTTPWiring> extends keyof In ? unknown : [
@@ -18,10 +18,6 @@ export type RunHTTPWiringOptions = Partial<{
18
18
  bubbleErrors: boolean;
19
19
  generateRequestId: () => string;
20
20
  }>;
21
- export type RunHTTPWiringParams = {
22
- singletonServices: CoreSingletonServices;
23
- createWireServices?: CreateWireServices<CoreSingletonServices, CoreServices<CoreSingletonServices>, CoreUserSession>;
24
- };
25
21
  /**
26
22
  * Represents the HTTP methods supported for API HTTP wirings.
27
23
  */
@@ -1,4 +1,4 @@
1
- import { Logger } from '../../services/index.js';
1
+ import type { Logger } from '../../services/index.js';
2
2
  /**
3
3
  * Logs all the loaded routes.
4
4
  * @param logger - A logger for logging information.
@@ -1,4 +1,4 @@
1
- import { HTTPMethod, PikkuHTTPRequest, PikkuQuery } from './http.types.js';
1
+ import type { HTTPMethod, PikkuHTTPRequest, PikkuQuery } from './http.types.js';
2
2
  /**
3
3
  * Abstract class representing a pikku request.
4
4
  * @template In - The type of the request body.
@@ -1,5 +1,5 @@
1
- import { PikkuHTTPResponse } from './http.types.js';
2
- import { SerializeOptions as CookieSerializeOptions } from 'cookie';
1
+ import type { PikkuHTTPResponse } from './http.types.js';
2
+ import type { SerializeOptions as CookieSerializeOptions } from 'cookie';
3
3
  export declare class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
4
4
  #private;
5
5
  setMode(mode: 'stream'): void;