@pikku/core 0.12.2 → 0.12.4

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 (282) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/crypto-utils.d.ts +10 -0
  3. package/dist/crypto-utils.js +62 -0
  4. package/dist/function/function-runner.js +4 -4
  5. package/dist/function/functions.types.d.ts +26 -1
  6. package/dist/function/functions.types.js +16 -0
  7. package/dist/handle-error.d.ts +1 -1
  8. package/dist/handle-error.js +7 -3
  9. package/dist/index.d.ts +14 -2
  10. package/dist/index.js +1 -1
  11. package/dist/pikku-state.js +3 -1
  12. package/dist/schema.js +1 -1
  13. package/dist/services/in-memory-workflow-service.d.ts +22 -3
  14. package/dist/services/in-memory-workflow-service.js +77 -1
  15. package/dist/services/workflow-service.d.ts +8 -2
  16. package/dist/testing/index.d.ts +2 -0
  17. package/dist/testing/index.js +1 -0
  18. package/dist/testing/service-tests.d.ts +31 -0
  19. package/dist/testing/service-tests.js +598 -0
  20. package/dist/types/core.types.d.ts +9 -1
  21. package/dist/types/state.types.d.ts +4 -2
  22. package/dist/utils/hash.d.ts +2 -0
  23. package/dist/utils/hash.js +23 -0
  24. package/dist/wirings/ai-agent/agent-dynamic-workflow.d.ts +6 -0
  25. package/dist/wirings/ai-agent/agent-dynamic-workflow.js +348 -0
  26. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +1 -1
  27. package/dist/wirings/ai-agent/ai-agent-memory.js +6 -5
  28. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -7
  29. package/dist/wirings/ai-agent/ai-agent-prepare.js +127 -47
  30. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +4 -0
  31. package/dist/wirings/ai-agent/ai-agent-runner.js +381 -27
  32. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +7 -2
  33. package/dist/wirings/ai-agent/ai-agent-stream.js +109 -46
  34. package/dist/wirings/ai-agent/ai-agent.types.d.ts +22 -1
  35. package/dist/wirings/ai-agent/index.d.ts +1 -2
  36. package/dist/wirings/ai-agent/index.js +1 -2
  37. package/dist/wirings/channel/channel-handler.js +5 -1
  38. package/dist/wirings/channel/channel.types.d.ts +1 -7
  39. package/dist/wirings/channel/local/local-channel-handler.d.ts +1 -1
  40. package/dist/wirings/channel/local/local-channel-handler.js +5 -3
  41. package/dist/wirings/channel/local/local-channel-runner.js +14 -4
  42. package/dist/wirings/channel/serverless/serverless-channel-runner.js +4 -1
  43. package/dist/wirings/cli/cli-runner.js +10 -2
  44. package/dist/wirings/cli/cli.types.d.ts +1 -0
  45. package/dist/wirings/http/http-routes.js +0 -1
  46. package/dist/wirings/http/http-runner.d.ts +1 -1
  47. package/dist/wirings/http/http-runner.js +25 -3
  48. package/dist/wirings/http/http.types.d.ts +3 -11
  49. package/dist/wirings/http/index.d.ts +2 -1
  50. package/dist/wirings/http/index.js +1 -0
  51. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -0
  52. package/dist/wirings/http/pikku-fetch-http-request.js +3 -0
  53. package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
  54. package/dist/wirings/http/pikku-fetch-http-response.js +4 -4
  55. package/dist/wirings/http/web-request.d.ts +12 -0
  56. package/dist/wirings/http/web-request.js +85 -0
  57. package/dist/wirings/mcp/mcp-endpoint-registry.js +1 -1
  58. package/dist/wirings/mcp/mcp-runner.js +13 -1
  59. package/dist/wirings/rpc/rpc-runner.d.ts +30 -6
  60. package/dist/wirings/rpc/rpc-runner.js +36 -14
  61. package/dist/wirings/rpc/rpc-types.d.ts +6 -1
  62. package/dist/wirings/rpc/wire-addon.d.ts +1 -0
  63. package/dist/wirings/rpc/wire-addon.js +1 -1
  64. package/dist/wirings/scheduler/scheduler-runner.js +1 -0
  65. package/dist/wirings/workflow/graph/graph-validation.d.ts +3 -0
  66. package/dist/wirings/workflow/graph/graph-validation.js +175 -0
  67. package/dist/wirings/workflow/graph/index.d.ts +1 -0
  68. package/dist/wirings/workflow/graph/index.js +1 -0
  69. package/dist/wirings/workflow/index.d.ts +1 -1
  70. package/dist/wirings/workflow/pikku-workflow-service.d.ts +8 -2
  71. package/dist/wirings/workflow/pikku-workflow-service.js +1 -2
  72. package/dist/wirings/workflow/workflow.types.d.ts +10 -1
  73. package/lcov.info +18891 -0
  74. package/package.json +4 -2
  75. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +0 -5
  76. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +0 -168
  77. package/src/crypto-utils.test.ts +0 -116
  78. package/src/crypto-utils.ts +0 -99
  79. package/src/errors/error-handler.ts +0 -62
  80. package/src/errors/error.test.ts +0 -195
  81. package/src/errors/errors.ts +0 -374
  82. package/src/errors/index.ts +0 -2
  83. package/src/factory-functions.test.ts +0 -109
  84. package/src/function/function-runner.test.ts +0 -536
  85. package/src/function/function-runner.ts +0 -365
  86. package/src/function/functions.types.ts +0 -267
  87. package/src/function/index.ts +0 -5
  88. package/src/handle-error.test.ts +0 -361
  89. package/src/handle-error.ts +0 -65
  90. package/src/index.ts +0 -104
  91. package/src/internal.ts +0 -6
  92. package/src/middleware/auth-apikey.test.ts +0 -363
  93. package/src/middleware/auth-apikey.ts +0 -47
  94. package/src/middleware/auth-bearer.test.ts +0 -450
  95. package/src/middleware/auth-bearer.ts +0 -72
  96. package/src/middleware/auth-cookie.test.ts +0 -528
  97. package/src/middleware/auth-cookie.ts +0 -80
  98. package/src/middleware/cors.test.ts +0 -424
  99. package/src/middleware/cors.ts +0 -104
  100. package/src/middleware/index.ts +0 -5
  101. package/src/middleware/remote-auth.test.ts +0 -488
  102. package/src/middleware/remote-auth.ts +0 -68
  103. package/src/middleware/timeout.ts +0 -15
  104. package/src/middleware-runner.test.ts +0 -418
  105. package/src/middleware-runner.ts +0 -234
  106. package/src/permissions.test.ts +0 -434
  107. package/src/permissions.ts +0 -319
  108. package/src/pikku-request.ts +0 -23
  109. package/src/pikku-response.ts +0 -5
  110. package/src/pikku-state.test.ts +0 -224
  111. package/src/pikku-state.ts +0 -214
  112. package/src/run-tests-script.test.ts +0 -49
  113. package/src/schema.test.ts +0 -249
  114. package/src/schema.ts +0 -151
  115. package/src/services/ai-agent-runner-service.ts +0 -41
  116. package/src/services/ai-run-state-service.ts +0 -20
  117. package/src/services/ai-storage-service.ts +0 -39
  118. package/src/services/content-service.ts +0 -76
  119. package/src/services/deployment-service.ts +0 -22
  120. package/src/services/gateway-service.ts +0 -20
  121. package/src/services/gopass-secrets.ts +0 -98
  122. package/src/services/in-memory-ai-run-state-service.ts +0 -73
  123. package/src/services/in-memory-trigger-service.ts +0 -64
  124. package/src/services/in-memory-workflow-service.test.ts +0 -351
  125. package/src/services/in-memory-workflow-service.ts +0 -395
  126. package/src/services/index.ts +0 -56
  127. package/src/services/jwt-service.ts +0 -30
  128. package/src/services/local-content.ts +0 -120
  129. package/src/services/local-gateway-service.ts +0 -62
  130. package/src/services/local-secrets.test.ts +0 -80
  131. package/src/services/local-secrets.ts +0 -94
  132. package/src/services/local-variables.test.ts +0 -61
  133. package/src/services/local-variables.ts +0 -39
  134. package/src/services/logger-console.test.ts +0 -118
  135. package/src/services/logger-console.ts +0 -98
  136. package/src/services/logger.ts +0 -57
  137. package/src/services/scheduler-service.ts +0 -86
  138. package/src/services/schema-service.ts +0 -33
  139. package/src/services/scoped-secret-service.test.ts +0 -74
  140. package/src/services/scoped-secret-service.ts +0 -41
  141. package/src/services/secret-service.ts +0 -38
  142. package/src/services/trigger-service.ts +0 -17
  143. package/src/services/typed-secret-service.test.ts +0 -93
  144. package/src/services/typed-secret-service.ts +0 -70
  145. package/src/services/typed-variables-service.test.ts +0 -73
  146. package/src/services/typed-variables-service.ts +0 -81
  147. package/src/services/user-session-service.test.ts +0 -113
  148. package/src/services/user-session-service.ts +0 -86
  149. package/src/services/variables-service.ts +0 -11
  150. package/src/services/workflow-service.ts +0 -84
  151. package/src/time-utils.test.ts +0 -56
  152. package/src/time-utils.ts +0 -107
  153. package/src/types/core.types.ts +0 -470
  154. package/src/types/state.types.ts +0 -186
  155. package/src/utils.test.ts +0 -350
  156. package/src/utils.ts +0 -129
  157. package/src/version.test.ts +0 -80
  158. package/src/version.ts +0 -25
  159. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +0 -363
  160. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +0 -238
  161. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +0 -152
  162. package/src/wirings/ai-agent/ai-agent-helpers.ts +0 -76
  163. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -309
  164. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +0 -115
  165. package/src/wirings/ai-agent/ai-agent-model-config.ts +0 -43
  166. package/src/wirings/ai-agent/ai-agent-prepare.ts +0 -522
  167. package/src/wirings/ai-agent/ai-agent-registry.test.ts +0 -37
  168. package/src/wirings/ai-agent/ai-agent-registry.ts +0 -82
  169. package/src/wirings/ai-agent/ai-agent-runner.test.ts +0 -317
  170. package/src/wirings/ai-agent/ai-agent-runner.ts +0 -251
  171. package/src/wirings/ai-agent/ai-agent-stream.test.ts +0 -652
  172. package/src/wirings/ai-agent/ai-agent-stream.ts +0 -1060
  173. package/src/wirings/ai-agent/ai-agent.types.ts +0 -360
  174. package/src/wirings/ai-agent/index.ts +0 -41
  175. package/src/wirings/channel/channel-common.ts +0 -90
  176. package/src/wirings/channel/channel-handler.ts +0 -241
  177. package/src/wirings/channel/channel-middleware-runner.ts +0 -120
  178. package/src/wirings/channel/channel-runner.ts +0 -166
  179. package/src/wirings/channel/channel-store.ts +0 -29
  180. package/src/wirings/channel/channel.types.ts +0 -178
  181. package/src/wirings/channel/define-channel-routes.ts +0 -25
  182. package/src/wirings/channel/eventhub-service.ts +0 -34
  183. package/src/wirings/channel/eventhub-store.ts +0 -13
  184. package/src/wirings/channel/index.ts +0 -24
  185. package/src/wirings/channel/local/index.ts +0 -3
  186. package/src/wirings/channel/local/local-channel-handler.ts +0 -79
  187. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -215
  188. package/src/wirings/channel/local/local-channel-runner.ts +0 -200
  189. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -95
  190. package/src/wirings/channel/local/local-eventhub-service.ts +0 -101
  191. package/src/wirings/channel/log-channels.ts +0 -20
  192. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +0 -54
  193. package/src/wirings/channel/pikku-abstract-channel-handler.ts +0 -45
  194. package/src/wirings/channel/serverless/index.ts +0 -5
  195. package/src/wirings/channel/serverless/serverless-channel-runner.ts +0 -286
  196. package/src/wirings/cli/channel/cli-channel-runner.ts +0 -136
  197. package/src/wirings/cli/channel/index.ts +0 -1
  198. package/src/wirings/cli/cli-runner.test.ts +0 -403
  199. package/src/wirings/cli/cli-runner.ts +0 -519
  200. package/src/wirings/cli/cli.types.ts +0 -357
  201. package/src/wirings/cli/command-parser.test.ts +0 -445
  202. package/src/wirings/cli/command-parser.ts +0 -504
  203. package/src/wirings/cli/define-cli-commands.ts +0 -24
  204. package/src/wirings/cli/index.ts +0 -19
  205. package/src/wirings/gateway/gateway-runner.test.ts +0 -474
  206. package/src/wirings/gateway/gateway-runner.ts +0 -411
  207. package/src/wirings/gateway/gateway.types.ts +0 -149
  208. package/src/wirings/gateway/index.ts +0 -13
  209. package/src/wirings/http/http-routes.test.ts +0 -322
  210. package/src/wirings/http/http-routes.ts +0 -198
  211. package/src/wirings/http/http-runner.test.ts +0 -144
  212. package/src/wirings/http/http-runner.ts +0 -563
  213. package/src/wirings/http/http.types.ts +0 -378
  214. package/src/wirings/http/index.ts +0 -25
  215. package/src/wirings/http/log-http-routes.ts +0 -22
  216. package/src/wirings/http/pikku-fetch-http-request.test.ts +0 -237
  217. package/src/wirings/http/pikku-fetch-http-request.ts +0 -166
  218. package/src/wirings/http/pikku-fetch-http-response.test.ts +0 -82
  219. package/src/wirings/http/pikku-fetch-http-response.ts +0 -147
  220. package/src/wirings/http/routers/http-router.ts +0 -13
  221. package/src/wirings/http/routers/path-to-regex.test.ts +0 -319
  222. package/src/wirings/http/routers/path-to-regex.ts +0 -126
  223. package/src/wirings/mcp/index.ts +0 -27
  224. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -389
  225. package/src/wirings/mcp/mcp-endpoint-registry.ts +0 -159
  226. package/src/wirings/mcp/mcp-runner.ts +0 -305
  227. package/src/wirings/mcp/mcp.types.ts +0 -216
  228. package/src/wirings/node/index.ts +0 -2
  229. package/src/wirings/node/node.types.ts +0 -23
  230. package/src/wirings/oauth2/index.ts +0 -3
  231. package/src/wirings/oauth2/oauth2-client.test.ts +0 -929
  232. package/src/wirings/oauth2/oauth2-client.ts +0 -335
  233. package/src/wirings/oauth2/oauth2.types.ts +0 -69
  234. package/src/wirings/oauth2/wire-oauth2-credential.ts +0 -23
  235. package/src/wirings/queue/index.ts +0 -31
  236. package/src/wirings/queue/queue-runner.test.ts +0 -710
  237. package/src/wirings/queue/queue-runner.ts +0 -192
  238. package/src/wirings/queue/queue.types.ts +0 -189
  239. package/src/wirings/queue/register-queue-helper.ts +0 -60
  240. package/src/wirings/queue/validate-worker-config.test.ts +0 -108
  241. package/src/wirings/queue/validate-worker-config.ts +0 -116
  242. package/src/wirings/rpc/index.ts +0 -4
  243. package/src/wirings/rpc/rpc-runner.ts +0 -439
  244. package/src/wirings/rpc/rpc-types.ts +0 -51
  245. package/src/wirings/rpc/wire-addon.ts +0 -20
  246. package/src/wirings/scheduler/index.ts +0 -11
  247. package/src/wirings/scheduler/log-schedulers.ts +0 -20
  248. package/src/wirings/scheduler/scheduler-runner.test.ts +0 -660
  249. package/src/wirings/scheduler/scheduler-runner.ts +0 -132
  250. package/src/wirings/scheduler/scheduler.types.ts +0 -53
  251. package/src/wirings/secret/index.ts +0 -9
  252. package/src/wirings/secret/secret.types.ts +0 -32
  253. package/src/wirings/secret/validate-secret-definitions.test.ts +0 -140
  254. package/src/wirings/secret/validate-secret-definitions.ts +0 -82
  255. package/src/wirings/trigger/index.ts +0 -10
  256. package/src/wirings/trigger/pikku-trigger-service.ts +0 -112
  257. package/src/wirings/trigger/trigger-runner.test.ts +0 -79
  258. package/src/wirings/trigger/trigger-runner.ts +0 -135
  259. package/src/wirings/trigger/trigger.types.ts +0 -178
  260. package/src/wirings/variable/index.ts +0 -8
  261. package/src/wirings/variable/validate-variable-definitions.test.ts +0 -91
  262. package/src/wirings/variable/validate-variable-definitions.ts +0 -69
  263. package/src/wirings/variable/variable.types.ts +0 -22
  264. package/src/wirings/workflow/dsl/index.ts +0 -31
  265. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +0 -320
  266. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -28
  267. package/src/wirings/workflow/graph/graph-node.ts +0 -222
  268. package/src/wirings/workflow/graph/graph-runner.test.ts +0 -487
  269. package/src/wirings/workflow/graph/graph-runner.ts +0 -816
  270. package/src/wirings/workflow/graph/index.ts +0 -14
  271. package/src/wirings/workflow/graph/template.test.ts +0 -49
  272. package/src/wirings/workflow/graph/template.ts +0 -42
  273. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -29
  274. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -104
  275. package/src/wirings/workflow/index.ts +0 -81
  276. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -200
  277. package/src/wirings/workflow/pikku-workflow-service.ts +0 -1165
  278. package/src/wirings/workflow/workflow-helpers.test.ts +0 -129
  279. package/src/wirings/workflow/workflow-helpers.ts +0 -79
  280. package/src/wirings/workflow/workflow.types.ts +0 -266
  281. package/tsconfig.json +0 -14
  282. package/tsconfig.tsbuildinfo +0 -1
@@ -1,563 +0,0 @@
1
- import type {
2
- CoreHTTPFunctionWiring,
3
- RunHTTPWiringOptions,
4
- PikkuHTTP,
5
- PikkuHTTPRequest,
6
- PikkuHTTPResponse,
7
- HTTPWiringMeta,
8
- HTTPMethod,
9
- } from './http.types.js'
10
- import type {
11
- CorePikkuFunction,
12
- CorePikkuFunctionSessionless,
13
- CorePikkuPermission,
14
- CorePermissionGroup,
15
- } from '../../function/functions.types.js'
16
- import type {
17
- CoreUserSession,
18
- CorePikkuMiddleware,
19
- CorePikkuMiddlewareGroup,
20
- WireServices,
21
- PikkuWire,
22
- PikkuWiringTypes,
23
- } from '../../types/core.types.js'
24
- import { NotFoundError, PikkuMissingMetaError } from '../../errors/errors.js'
25
- import {
26
- closeWireServices,
27
- createWeakUID,
28
- isSerializable,
29
- } from '../../utils.js'
30
- import {
31
- getSingletonServices,
32
- getCreateWireServices,
33
- } from '../../pikku-state.js'
34
- import { PikkuSessionService } from '../../services/user-session-service.js'
35
- import { handleHTTPError } from '../../handle-error.js'
36
- import { pikkuState } from '../../pikku-state.js'
37
- import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
38
- import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js'
39
- import type { PikkuChannel } from '../channel/channel.types.js'
40
- import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
41
- import { httpRouter } from './routers/http-router.js'
42
- import { validateSchema } from '../../schema.js'
43
- import { runMiddleware } from '../../middleware-runner.js'
44
-
45
- /**
46
- * Extract headers from a PikkuHTTPRequest based on the schema keys
47
- */
48
- function extractHeadersFromRequest(
49
- request: PikkuHTTPRequest,
50
- headerKeys: string[]
51
- ): Record<string, string | string[] | undefined> {
52
- const headers: Record<string, string | string[] | undefined> = {}
53
- for (const headerName of headerKeys) {
54
- const value = request.header(headerName)
55
- if (value !== null) {
56
- headers[headerName] = value
57
- }
58
- }
59
- return headers
60
- }
61
-
62
- /**
63
- * Registers HTTP middleware for a specific route pattern.
64
- *
65
- * This function registers middleware at runtime that will be applied to
66
- * HTTP routes matching the specified pattern.
67
- *
68
- * For tree-shaking benefits, wrap in a factory function:
69
- * `export const x = () => addHTTPMiddleware('pattern', [...])`
70
- *
71
- * @template PikkuMiddleware The middleware type.
72
- * @param {string} pattern - Route pattern (e.g., '*' for all routes, '/api/*' for specific routes).
73
- * @param {CorePikkuMiddlewareGroup} middleware - Array of middleware for this route pattern.
74
- *
75
- * @returns {CorePikkuMiddlewareGroup} The middleware array (for chaining/wrapping).
76
- *
77
- * @example
78
- * ```typescript
79
- * // Recommended: tree-shakeable
80
- * export const httpGlobal = () => addHTTPMiddleware('*', [
81
- * corsMiddleware,
82
- * loggingMiddleware
83
- * ])
84
- *
85
- * // Also works: no tree-shaking
86
- * export const apiMiddleware = addHTTPMiddleware('/api/*', [
87
- * authMiddleware
88
- * ])
89
- * ```
90
- */
91
- export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
92
- pattern: string,
93
- middleware: CorePikkuMiddlewareGroup,
94
- packageName: string | null = null
95
- ): CorePikkuMiddlewareGroup => {
96
- const httpGroups = pikkuState(packageName, 'middleware', 'httpGroup')
97
- httpGroups[pattern] = middleware
98
- return middleware
99
- }
100
-
101
- /**
102
- * Registers HTTP permissions for a specific route pattern.
103
- *
104
- * This function registers permissions at runtime that will be applied to
105
- * HTTP routes matching the specified pattern.
106
- *
107
- * For tree-shaking benefits, wrap in a factory function:
108
- * `export const x = () => addHTTPPermission('pattern', [...])`
109
- *
110
- * @template PikkuPermission The permission type.
111
- * @param {string} pattern - Route pattern (e.g., '*' for all routes, '/api/*' for specific routes).
112
- * @param {CorePermissionGroup | CorePikkuPermission[]} permissions - Permissions for this route pattern.
113
- *
114
- * @returns {CorePermissionGroup | CorePikkuPermission[]} The permissions (for chaining/wrapping).
115
- *
116
- * @example
117
- * ```typescript
118
- * // Recommended: tree-shakeable
119
- * export const httpGlobalPermissions = () => addHTTPPermission('*', [
120
- * authenticatedPermission,
121
- * rateLimitPermission
122
- * ])
123
- *
124
- * // Also works: no tree-shaking
125
- * export const apiPermissions = addHTTPPermission('/api/*', [
126
- * adminPermission
127
- * ])
128
- * ```
129
- */
130
- export const addHTTPPermission = <PikkuPermission extends CorePikkuPermission>(
131
- pattern: string,
132
- permissions: CorePermissionGroup | CorePikkuPermission[],
133
- packageName: string | null = null
134
- ): CorePermissionGroup | CorePikkuPermission[] => {
135
- const httpGroups = pikkuState(packageName, 'permissions', 'httpGroup')
136
- httpGroups[pattern] = permissions
137
- return permissions
138
- }
139
-
140
- /**
141
- * Adds a new route to the global HTTP route registry.
142
- *
143
- * The route configuration includes the HTTP method, route path, permissions,
144
- * middleware, and the handler function that implements the route's logic.
145
- *
146
- * @template In Expected input type.
147
- * @template Out Expected output type.
148
- * @template Route Route pattern as a string.
149
- * @template PikkuFunction Type for the route handler function.
150
- * @template PikkuFunctionSessionless Type for a sessionless handler.
151
- * @template PikkuPermissionGroup Type representing required permissions.
152
- * @template PikkuMiddleware Middleware type to be used with the route.
153
- * @param {CoreHTTPFunctionWiring<In, Out, Route, PikkuFunction, PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware>} httpWiring - The HTTP wiring configuration object.
154
- */
155
- export const wireHTTP = <
156
- In,
157
- Out,
158
- Route extends string,
159
- PikkuFunction extends CorePikkuFunction<In, Out> = CorePikkuFunction<In, Out>,
160
- PikkuFunctionSessionless extends CorePikkuFunctionSessionless<
161
- In,
162
- Out
163
- > = CorePikkuFunctionSessionless<In, Out>,
164
- PikkuPermissionGroup extends
165
- CorePikkuPermission<In> = CorePikkuPermission<In>,
166
- PikkuMiddleware extends CorePikkuMiddleware = CorePikkuMiddleware,
167
- >(
168
- httpWiring: CoreHTTPFunctionWiring<
169
- In,
170
- Out,
171
- Route,
172
- PikkuFunction,
173
- PikkuFunctionSessionless,
174
- PikkuPermissionGroup,
175
- PikkuMiddleware
176
- >
177
- ) => {
178
- const httpMeta = pikkuState(null, 'http', 'meta')
179
- const routeMeta = httpMeta[httpWiring.method][httpWiring.route]
180
- if (!routeMeta) {
181
- throw new PikkuMissingMetaError(
182
- `Missing generated metadata for HTTP route '${httpWiring.method.toUpperCase()} ${httpWiring.route}'`
183
- )
184
- }
185
- if (httpWiring.func) {
186
- addFunction(routeMeta.pikkuFuncId, httpWiring.func)
187
- }
188
- const routes = pikkuState(null, 'http', 'routes')
189
- if (!routes.has(httpWiring.method)) {
190
- routes.set(httpWiring.method, new Map())
191
- }
192
- pikkuState(null, 'http', 'routes')
193
- .get(httpWiring.method)
194
- ?.set(httpWiring.route, httpWiring as any)
195
- }
196
-
197
- /**
198
- * Finds a matching route based on the HTTP method and URL path.
199
- *
200
- * Iterates over all registered routes, skipping those with a mismatched method.
201
- * When a route pattern matches the incoming request path, this function aggregates
202
- * any global middleware along with route-specific middleware and identifies any input schema.
203
- *
204
- * @param {string} requestType - The HTTP method (e.g., GET, POST).
205
- * @param {string} requestPath - The URL path of the incoming request.
206
- * @returns {Object | undefined} An object with matched route details or undefined if no match.
207
- */
208
- const getMatchingRoute = (requestType: string, requestPath: string) => {
209
- const matchedPath = httpRouter.match(
210
- requestType.toLowerCase() as HTTPMethod,
211
- requestPath
212
- )
213
-
214
- if (matchedPath) {
215
- const route = pikkuState(null, 'http', 'routes')
216
- .get(requestType.toLowerCase() as HTTPMethod)!
217
- .get(matchedPath.route)!
218
- const meta = pikkuState(null, 'http', 'meta')[
219
- requestType.toLowerCase() as PikkuWiringTypes
220
- ][route.route]
221
-
222
- return {
223
- matchedPath,
224
- params: matchedPath.params,
225
- route,
226
- permissions: route.permissions,
227
- meta: meta!,
228
- }
229
- }
230
- }
231
-
232
- /**
233
- * Combines the request and response objects into a single HTTP wire object.
234
- *
235
- * This utility function creates an object that holds both the HTTP request and response,
236
- * which simplifies passing these around through middleware and route execution.
237
- *
238
- * @param {PikkuHTTPRequest | undefined} request - The HTTP request object.
239
- * @param {PikkuHTTPResponse | undefined} response - The HTTP response object.
240
- * @returns {PikkuHTTP | undefined} The combined HTTP wire object or undefined if none provided.
241
- */
242
- export const createHTTPWire = (
243
- request: PikkuHTTPRequest | undefined,
244
- response: PikkuHTTPResponse | undefined
245
- ): PikkuHTTP | undefined => {
246
- let http: PikkuHTTP | undefined = undefined
247
-
248
- if (request || response) {
249
- http = {}
250
- if (request) {
251
- http.request = request
252
- }
253
- if (response) {
254
- http.response = response
255
- }
256
- }
257
-
258
- return http
259
- }
260
-
261
- /**
262
- * Validates the input data and executes the route handler
263
- *
264
- * This function performs these steps:
265
- * 1. Sets URL parameters on the request.
266
- * 2. Validates the user session if required.
267
- * 3. Creates session-specific services.
268
- * 4. Validates the incoming data against a schema.
269
- * 5. Optionally coerces query string values to arrays.
270
- * 6. Checks route-specific permissions.
271
- * 7. Executes the route handler.
272
- * 8. Sends the appropriate response.
273
- *
274
- * @param {Object} services - A collection of shared services and utilities.
275
- * @param {Object} matchedRoute - Contains route details, URL parameters, and optional schema.
276
- * @param {PikkuHTTP | undefined} http - The HTTP wire object.
277
- * @param {Object} options - Options for route execution (e.g., whether to coerce query strings to arrays).
278
- * @returns {Promise<any>} An object containing the route handler result and wire services (if any).
279
- * @throws Throws errors like MissingSessionError or ForbiddenError on validation failures.
280
- */
281
- const executeRoute = async (
282
- services: {
283
- singletonServices: any
284
- createWireServices?: any
285
- skipUserSession: boolean
286
- requestId: string
287
- },
288
- matchedRoute: {
289
- matchedPath: any
290
- params: any
291
- route: CoreHTTPFunctionWiring<any, any, any>
292
- meta: HTTPWiringMeta
293
- },
294
- http: PikkuHTTP,
295
- options: {
296
- coerceDataFromSchema: boolean
297
- }
298
- ) => {
299
- const userSession = new PikkuSessionService<CoreUserSession>()
300
- const { params, route, meta } = matchedRoute
301
- const { singletonServices, createWireServices, skipUserSession, requestId } =
302
- services
303
-
304
- // Attach URL parameters to the request object
305
- http?.request?.setParams(params)
306
-
307
- // Validate request headers if schema is defined
308
- if (meta.headersSchemaName && http.request && singletonServices.schema) {
309
- const headerKeys = singletonServices.schema.getSchemaKeys(
310
- meta.headersSchemaName
311
- )
312
- const rawHeaders = extractHeadersFromRequest(http.request, headerKeys)
313
- await validateSchema(
314
- singletonServices.logger,
315
- singletonServices.schema,
316
- meta.headersSchemaName,
317
- rawHeaders
318
- )
319
- }
320
-
321
- const requiresSession = route.auth !== false
322
- let wireServices: any
323
- let result: any
324
-
325
- singletonServices.logger.info(
326
- `Matched route: ${route.route} | method: ${route.method.toUpperCase()} | auth: ${requiresSession.toString()}`
327
- )
328
-
329
- // Ensure session is available when required
330
- if (skipUserSession && requiresSession) {
331
- throw new Error("Can't skip trying to get user session if auth is required")
332
- }
333
-
334
- let cachedData: unknown | undefined
335
- const data = async () => {
336
- if (cachedData === undefined) {
337
- cachedData = await http.request!.data()
338
- }
339
- return cachedData
340
- }
341
- let channel: PikkuChannel<unknown, unknown> | undefined
342
-
343
- if (matchedRoute.route.sse) {
344
- const response = http?.response
345
- if (!response) {
346
- throw new Error('SSE requires a valid HTTP response object')
347
- }
348
- if (!response.setMode) {
349
- throw new Error('Response object does not support SSE mode')
350
- }
351
- response.setMode('stream')
352
- response.header('Content-Type', 'text/event-stream')
353
- response.header('Cache-Control', 'no-cache')
354
- response.header('Connection', 'keep-alive')
355
- response.header('Transfer-Encoding', 'chunked')
356
- channel = {
357
- channelId: requestId,
358
- openingData: await data(),
359
- send: (data: any) => {
360
- response.arrayBuffer(isSerializable(data) ? JSON.stringify(data) : data)
361
- },
362
- sendBinary: (data) => {
363
- response.arrayBuffer(data)
364
- },
365
- close: () => {
366
- channel!.state = 'closed'
367
- response.close?.()
368
- },
369
- state: 'open',
370
- }
371
- }
372
-
373
- const wire: PikkuWire = {
374
- http,
375
- channel,
376
- session: userSession.get() as CoreUserSession | undefined,
377
- setSession: (s: any) => userSession.setInitial(s),
378
- getSession: () => userSession.get(),
379
- hasSessionChanged: () => userSession.sessionChanged,
380
- }
381
-
382
- result = await runPikkuFunc(
383
- 'http',
384
- `${meta.method}:${meta.route}`,
385
- meta.pikkuFuncId,
386
- {
387
- singletonServices,
388
- createWireServices,
389
- auth: route.auth !== false,
390
- data,
391
- inheritedMiddleware: meta.middleware,
392
- wireMiddleware: route.middleware,
393
- inheritedPermissions: meta.permissions,
394
- wirePermissions: route.permissions,
395
- coerceDataFromSchema: options.coerceDataFromSchema,
396
- tags: route.tags,
397
- wire,
398
- sessionService: userSession,
399
- }
400
- )
401
- if (!matchedRoute.route.sse) {
402
- if (result === undefined || result === null) {
403
- http?.response?.status(204)
404
- } else if (route.returnsJSON === false) {
405
- http?.response?.arrayBuffer(result)
406
- } else {
407
- http?.response?.status(200)
408
- http?.response?.json(result)
409
- }
410
- }
411
-
412
- return wireServices ? { result, wireServices } : { result }
413
- }
414
-
415
- /**
416
- * Executes an HTTP route for a given Fetch API request.
417
- *
418
- * This function wraps the entire lifecycle of handling an HTTP request:
419
- * - Matching the request to a registered route.
420
- * - Validating input and session state.
421
- * - Running middleware and the route handler.
422
- * - Handling errors and forming the response.
423
- *
424
- * @template In Expected input data type.
425
- * @template Out Expected output data type.
426
- * @param {Request} request - The native Fetch API Request object.
427
- * @param {RunHTTPWiringOptions} params - Additional options including services and session management.
428
- * @returns {Promise<Response>} A promise that resolves to a Fetch API Response object.
429
- */
430
- export const fetch = async <In, Out>(
431
- request: Request,
432
- params: RunHTTPWiringOptions = {}
433
- ): Promise<Response> => {
434
- const pikkuResponse = new PikkuFetchHTTPResponse()
435
- await fetchData<In, Out>(request, pikkuResponse, params)
436
- return pikkuResponse.toResponse()
437
- }
438
-
439
- /**
440
- * Executes an HTTP route using a Pikku-specific request wrapper.
441
- *
442
- * This variant accepts either a native Request or a PikkuHTTPRequest object and returns
443
- * a PikkuFetchHTTPResponse for further manipulation if needed.
444
- *
445
- * @template In Expected input data type.
446
- * @template Out Expected output data type.
447
- * @param {Request | PikkuHTTPRequest} request - The request object.
448
- * @param {RunHTTPWiringOptions} params - Execution options including services and session configuration.
449
- * @returns {Promise<PikkuFetchHTTPResponse>} A promise that resolves to a PikkuFetchHTTPResponse object.
450
- */
451
- export const pikkuFetch = async <In, Out>(
452
- request: Request | PikkuHTTPRequest,
453
- params: RunHTTPWiringOptions = {}
454
- ): Promise<PikkuFetchHTTPResponse> => {
455
- const pikkuResponse = new PikkuFetchHTTPResponse()
456
- await fetchData<In, Out>(request, pikkuResponse, params)
457
- return pikkuResponse
458
- }
459
-
460
- /**
461
- * Core function to process an HTTP request through route matching, validation,
462
- * middleware execution, error handling, and session service cleanup.
463
- *
464
- * This function does the following:
465
- * - Wraps the incoming request and response into an HTTP wire object.
466
- * - Determines the correct route based on HTTP method and path.
467
- * - Executes middleware and the route handler.
468
- * - Catches and handles errors, optionally bubbling them if configured.
469
- * - Cleans up any wire services created during processing.
470
- *
471
- * @template In Expected input data type.
472
- * @template Out Expected output data type.
473
- * @param {Request | PikkuHTTPRequest} request - The incoming HTTP request.
474
- * @param {PikkuHTTPResponse} response - The response object to be populated.
475
- * @param {RunHTTPWiringOptions} options - Options such as singleton services, session handling, and error configuration.
476
- * @returns {Promise<Out | void>} The output from the route handler or void if an error occurred.
477
- */
478
- export const fetchData = async <In, Out>(
479
- request: Request | PikkuHTTPRequest,
480
- response: PikkuHTTPResponse,
481
- {
482
- skipUserSession = false,
483
- respondWith404 = true,
484
- logWarningsForStatusCodes = [],
485
- coerceDataFromSchema = true,
486
- bubbleErrors = false,
487
- generateRequestId,
488
- }: RunHTTPWiringOptions = {}
489
- ): Promise<Out | void> => {
490
- const singletonServices = getSingletonServices()
491
- const createWireServices = getCreateWireServices()
492
- let wireServices: WireServices<typeof singletonServices> | undefined
493
- let result: Out
494
-
495
- // Combine the request and response into one wire object
496
- const pikkuRequest =
497
- request instanceof Request ? new PikkuFetchHTTPRequest(request) : request
498
- let requestId: string | null = null
499
- try {
500
- requestId = pikkuRequest.header('x-request-id')
501
- } catch {}
502
- requestId = requestId || generateRequestId?.() || createWeakUID()
503
- const http = createHTTPWire(pikkuRequest, response)
504
- const apiType = http!.request!.method()
505
- const apiRoute = http!.request!.path()
506
-
507
- // Locate the matching route based on the HTTP method and path
508
- const matchedRoute = getMatchingRoute(apiType, apiRoute)
509
- try {
510
- if (!matchedRoute) {
511
- if (apiType.toLowerCase() === 'options') {
512
- const httpGroups = pikkuState(null, 'middleware', 'httpGroup')
513
- const globalMiddleware = httpGroups['*']
514
- const wire: PikkuWire = { http: http! }
515
- if (globalMiddleware) {
516
- await runMiddleware(
517
- singletonServices,
518
- wire,
519
- globalMiddleware as CorePikkuMiddleware[]
520
- )
521
- }
522
- response.status(204).json(undefined as any)
523
- return
524
- }
525
- singletonServices.logger.info({
526
- message: 'Route not found',
527
- apiRoute,
528
- apiType,
529
- })
530
- throw new NotFoundError(`Route not found: ${apiRoute}`)
531
- }
532
-
533
- // Execute the matched route along with its middleware and session management
534
- ;({ result, wireServices } = await executeRoute(
535
- {
536
- singletonServices,
537
- createWireServices,
538
- skipUserSession,
539
- requestId,
540
- },
541
- matchedRoute,
542
- http!,
543
- { coerceDataFromSchema }
544
- ))
545
-
546
- return result
547
- } catch (e: any) {
548
- handleHTTPError(
549
- e,
550
- http,
551
- requestId,
552
- singletonServices.logger,
553
- logWarningsForStatusCodes,
554
- respondWith404,
555
- bubbleErrors
556
- )
557
- } finally {
558
- // Clean up any session-specific services created during processing
559
- if (wireServices) {
560
- await closeWireServices(singletonServices.logger, wireServices)
561
- }
562
- }
563
- }