@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,224 @@
1
+ import { describe, test, beforeEach } from 'node:test'
2
+ import assert from 'node:assert'
3
+ import {
4
+ pikkuState,
5
+ resetPikkuState,
6
+ initializePikkuState,
7
+ getAllPackageStates,
8
+ getSingletonServices,
9
+ getCreateWireServices,
10
+ getPikkuMetaDir,
11
+ addPackageServiceFactories,
12
+ } from './pikku-state.js'
13
+
14
+ beforeEach(() => {
15
+ resetPikkuState()
16
+ })
17
+
18
+ describe('pikkuState', () => {
19
+ test('should get state for main package with null name', () => {
20
+ const functions = pikkuState(null, 'function', 'functions')
21
+ assert.ok(functions instanceof Map)
22
+ })
23
+
24
+ test('should get state for main package with __main__ name', () => {
25
+ const functions = pikkuState('__main__', 'function', 'functions')
26
+ assert.ok(functions instanceof Map)
27
+ })
28
+
29
+ test('should set and get state values', () => {
30
+ const testMeta = { key: 'value' }
31
+ pikkuState(null, 'function', 'meta', testMeta as any)
32
+ const result = pikkuState(null, 'function', 'meta')
33
+ assert.deepStrictEqual(result, testMeta)
34
+ })
35
+
36
+ test('should auto-initialize package state on first access', () => {
37
+ const states = getAllPackageStates()
38
+ assert.ok(!states.has('@test/package'))
39
+
40
+ pikkuState('@test/package', 'function', 'functions')
41
+
42
+ assert.ok(states.has('@test/package'))
43
+ })
44
+
45
+ test('should isolate state between packages', () => {
46
+ pikkuState(null, 'function', 'meta', { main: true } as any)
47
+ pikkuState('@addon/pkg', 'function', 'meta', { addon: true } as any)
48
+
49
+ assert.deepStrictEqual(pikkuState(null, 'function', 'meta'), { main: true })
50
+ assert.deepStrictEqual(pikkuState('@addon/pkg', 'function', 'meta'), {
51
+ addon: true,
52
+ })
53
+ })
54
+
55
+ test('should return correct state types', () => {
56
+ const httpRoutes = pikkuState(null, 'http', 'routes')
57
+ assert.ok(httpRoutes instanceof Map)
58
+
59
+ const schemas = pikkuState(null, 'misc', 'schemas')
60
+ assert.ok(schemas instanceof Map)
61
+
62
+ const errors = pikkuState(null, 'misc', 'errors')
63
+ assert.ok(errors instanceof Map)
64
+ })
65
+ })
66
+
67
+ describe('getAllPackageStates', () => {
68
+ test('should return a Map', () => {
69
+ const states = getAllPackageStates()
70
+ assert.ok(states instanceof Map)
71
+ })
72
+
73
+ test('should contain __main__ after reset', () => {
74
+ const states = getAllPackageStates()
75
+ assert.ok(states.has('__main__'))
76
+ })
77
+
78
+ test('should return same reference on multiple calls', () => {
79
+ const states1 = getAllPackageStates()
80
+ const states2 = getAllPackageStates()
81
+ assert.strictEqual(states1, states2)
82
+ })
83
+ })
84
+
85
+ describe('initializePikkuState', () => {
86
+ test('should create a new package state', () => {
87
+ const states = getAllPackageStates()
88
+ assert.ok(!states.has('@new/package'))
89
+
90
+ initializePikkuState('@new/package')
91
+
92
+ assert.ok(states.has('@new/package'))
93
+ })
94
+
95
+ test('should not overwrite existing package state', () => {
96
+ pikkuState('@existing/pkg', 'function', 'meta', { test: true } as any)
97
+
98
+ initializePikkuState('@existing/pkg')
99
+
100
+ const meta = pikkuState('@existing/pkg', 'function', 'meta')
101
+ assert.deepStrictEqual(meta, { test: true })
102
+ })
103
+ })
104
+
105
+ describe('resetPikkuState', () => {
106
+ test('should clear all package states', () => {
107
+ initializePikkuState('@addon/one')
108
+ initializePikkuState('@addon/two')
109
+ assert.ok(getAllPackageStates().has('@addon/one'))
110
+
111
+ resetPikkuState()
112
+
113
+ assert.ok(!getAllPackageStates().has('@addon/one'))
114
+ assert.ok(!getAllPackageStates().has('@addon/two'))
115
+ })
116
+
117
+ test('should preserve errors map from __main__', () => {
118
+ const errors = pikkuState(null, 'misc', 'errors')
119
+ errors.set('TestError', { status: 400, message: 'test' })
120
+
121
+ resetPikkuState()
122
+
123
+ const restoredErrors = pikkuState(null, 'misc', 'errors')
124
+ assert.strictEqual(restoredErrors.get('TestError')?.message, 'test')
125
+ })
126
+
127
+ test('should re-initialize __main__ package', () => {
128
+ resetPikkuState()
129
+
130
+ const states = getAllPackageStates()
131
+ assert.ok(states.has('__main__'))
132
+ assert.ok(pikkuState(null, 'function', 'functions') instanceof Map)
133
+ })
134
+
135
+ test('should create fresh state objects after reset', () => {
136
+ const functionsBefore = pikkuState(null, 'function', 'functions')
137
+ functionsBefore.set('testFunc', {} as any)
138
+
139
+ resetPikkuState()
140
+
141
+ const functionsAfter = pikkuState(null, 'function', 'functions')
142
+ assert.strictEqual(functionsAfter.size, 0)
143
+ })
144
+ })
145
+
146
+ describe('getSingletonServices', () => {
147
+ test('should throw when singleton services not initialized', () => {
148
+ assert.throws(() => getSingletonServices(), {
149
+ message: 'Singleton services not initialized',
150
+ })
151
+ })
152
+
153
+ test('should return services when initialized', () => {
154
+ const mockServices = { logger: { info: () => {} } }
155
+ pikkuState(null, 'package', 'singletonServices', mockServices as any)
156
+
157
+ const result = getSingletonServices()
158
+ assert.strictEqual(result, mockServices)
159
+ })
160
+ })
161
+
162
+ describe('getCreateWireServices', () => {
163
+ test('should return undefined when no factories set', () => {
164
+ const result = getCreateWireServices()
165
+ assert.strictEqual(result, undefined)
166
+ })
167
+
168
+ test('should return createWireServices when factories set', () => {
169
+ const mockCreateWire = async () => ({})
170
+ pikkuState(null, 'package', 'factories', {
171
+ createWireServices: mockCreateWire,
172
+ } as any)
173
+
174
+ const result = getCreateWireServices()
175
+ assert.strictEqual(result, mockCreateWire)
176
+ })
177
+ })
178
+
179
+ describe('getPikkuMetaDir', () => {
180
+ test('should return null by default', () => {
181
+ const result = getPikkuMetaDir()
182
+ assert.strictEqual(result, null)
183
+ })
184
+
185
+ test('should return metaDir when set', () => {
186
+ pikkuState(null, 'package', 'metaDir', '/some/path' as any)
187
+ const result = getPikkuMetaDir()
188
+ assert.strictEqual(result, '/some/path')
189
+ })
190
+
191
+ test('should return metaDir for specific package', () => {
192
+ pikkuState('@test/pkg', 'package', 'metaDir', '/addon/path' as any)
193
+ const result = getPikkuMetaDir('@test/pkg')
194
+ assert.strictEqual(result, '/addon/path')
195
+ })
196
+
197
+ test('should treat null packageName as main', () => {
198
+ pikkuState(null, 'package', 'metaDir', '/main/path' as any)
199
+ const result = getPikkuMetaDir(null)
200
+ assert.strictEqual(result, '/main/path')
201
+ })
202
+ })
203
+
204
+ describe('addPackageServiceFactories', () => {
205
+ test('should register factories for addon package', () => {
206
+ const mockFactories = {
207
+ createSingletonServices: async () => ({}),
208
+ createWireServices: async () => ({}),
209
+ }
210
+
211
+ addPackageServiceFactories('@addon/pkg', mockFactories as any)
212
+
213
+ const result = pikkuState('@addon/pkg', 'package', 'factories')
214
+ assert.strictEqual(result, mockFactories)
215
+ })
216
+
217
+ test('should not affect main package factories', () => {
218
+ const addonFactories = { createSingletonServices: async () => ({}) }
219
+ addPackageServiceFactories('@addon/pkg', addonFactories as any)
220
+
221
+ const mainFactories = pikkuState(null, 'package', 'factories')
222
+ assert.strictEqual(mainFactories, null)
223
+ })
224
+ })
@@ -1,23 +1,32 @@
1
- import { PikkuPackageState } from './index.js'
2
- import { HTTPWiringsMeta } from './wirings/http/http.types.js'
3
- import {
1
+ import type { PikkuPackageState } from './index.js'
2
+ import type {
3
+ CoreSingletonServices,
4
+ CreateWireServices,
5
+ } from './types/core.types.js'
6
+ import type { HTTPWiringsMeta } from './wirings/http/http.types.js'
7
+ import type {
4
8
  MCPResourceMeta,
5
9
  MCPToolMeta,
6
10
  MCPPromptMeta,
7
11
  } from './wirings/mcp/mcp.types.js'
8
- import { AIAgentMeta } from './wirings/ai-agent/ai-agent.types.js'
9
- import { ScheduledTasksMeta } from './wirings/scheduler/scheduler.types.js'
10
- import { TriggerMeta } from './wirings/trigger/trigger.types.js'
12
+ import type { AIAgentMeta } from './wirings/ai-agent/ai-agent.types.js'
13
+ import type { GatewaysMeta } from './wirings/gateway/gateway.types.js'
14
+ import type { ScheduledTasksMeta } from './wirings/scheduler/scheduler.types.js'
15
+ import type { TriggerMeta } from './wirings/trigger/trigger.types.js'
11
16
 
12
- declare global {
13
- // eslint-disable-next-line no-var
14
- var pikkuState: Map<string, PikkuPackageState> | undefined
17
+ const PIKKU_STATE_KEY = Symbol.for('@pikku/core/state')
18
+
19
+ export const getAllPackageStates = (): Map<string, PikkuPackageState> => {
20
+ if (!(globalThis as any)[PIKKU_STATE_KEY]) {
21
+ ;(globalThis as any)[PIKKU_STATE_KEY] = new Map<string, PikkuPackageState>()
22
+ }
23
+ return (globalThis as any)[PIKKU_STATE_KEY] as Map<string, PikkuPackageState>
15
24
  }
16
25
 
17
26
  /**
18
27
  * Get or set package-scoped pikku state
19
28
  *
20
- * @param packageName - Package name (null for main package, '@scope/package' for external packages)
29
+ * @param packageName - Package name (null for main package, '@scope/package' for addon packages)
21
30
  * @param type - State category (function, rpc, http, etc.)
22
31
  * @param content - Content key within the category
23
32
  * @param value - Optional value to set
@@ -27,7 +36,7 @@ declare global {
27
36
  * // Main package
28
37
  * pikkuState(null, 'function', 'functions').get(funcName)
29
38
  *
30
- * // External package
39
+ * // Addon package
31
40
  * pikkuState('@acme/stripe-functions', 'rpc', 'meta')
32
41
  */
33
42
  export const pikkuState = <
@@ -42,14 +51,11 @@ export const pikkuState = <
42
51
  const resolvedPackageName = packageName ?? '__main__'
43
52
 
44
53
  // Initialize package state if it doesn't exist
45
- if (
46
- !globalThis.pikkuState ||
47
- !globalThis.pikkuState.has(resolvedPackageName)
48
- ) {
54
+ if (!getAllPackageStates().has(resolvedPackageName)) {
49
55
  initializePikkuState(resolvedPackageName)
50
56
  }
51
57
 
52
- const packageState = globalThis.pikkuState!.get(resolvedPackageName)!
58
+ const packageState = getAllPackageStates().get(resolvedPackageName)!
53
59
 
54
60
  if (value !== undefined) {
55
61
  packageState[type][content] = value
@@ -66,7 +72,7 @@ const createEmptyPackageState = (): PikkuPackageState => ({
66
72
  rpc: {
67
73
  meta: {},
68
74
  files: new Map(),
69
- externalPackages: new Map(),
75
+ addons: new Map(),
70
76
  },
71
77
  http: {
72
78
  middleware: new Map(),
@@ -116,6 +122,10 @@ const createEmptyPackageState = (): PikkuPackageState => ({
116
122
  agents: new Map(),
117
123
  agentsMeta: {} as AIAgentMeta,
118
124
  },
125
+ gateway: {
126
+ gateways: new Map(),
127
+ meta: {} as GatewaysMeta,
128
+ },
119
129
  cli: {
120
130
  meta: { programs: {}, renderers: {} },
121
131
  programs: {},
@@ -152,29 +162,26 @@ const createEmptyPackageState = (): PikkuPackageState => ({
152
162
  * Initialize state for a new package
153
163
  */
154
164
  export const initializePikkuState = (packageName: string): void => {
155
- if (!globalThis.pikkuState) {
156
- globalThis.pikkuState = new Map()
157
- }
158
- if (!globalThis.pikkuState.has(packageName)) {
159
- globalThis.pikkuState.set(packageName, createEmptyPackageState())
165
+ if (!getAllPackageStates().has(packageName)) {
166
+ getAllPackageStates().set(packageName, createEmptyPackageState())
160
167
  }
161
168
  }
162
169
 
163
170
  export const resetPikkuState = () => {
164
171
  // Preserve the errors map before resetting
165
- const existingErrors = globalThis.pikkuState?.get('__main__')?.misc.errors
172
+ const existingErrors = getAllPackageStates().get('__main__')?.misc.errors
166
173
 
167
- globalThis.pikkuState = new Map()
174
+ ;(globalThis as any)[PIKKU_STATE_KEY] = new Map<string, PikkuPackageState>()
168
175
  initializePikkuState('__main__')
169
176
 
170
177
  // Restore the errors map if it existed
171
178
  if (existingErrors) {
172
- const mainState = globalThis.pikkuState.get('__main__')!
179
+ const mainState = getAllPackageStates().get('__main__')!
173
180
  mainState.misc.errors = existingErrors
174
181
  }
175
182
  }
176
183
 
177
- if (!globalThis.pikkuState) {
184
+ if (!getAllPackageStates().has('__main__')) {
178
185
  resetPikkuState()
179
186
  }
180
187
 
@@ -182,11 +189,21 @@ export const getPikkuMetaDir = (packageName?: string | null): string | null => {
182
189
  return pikkuState(packageName ?? null, 'package', 'metaDir')
183
190
  }
184
191
 
192
+ export const getSingletonServices = (): CoreSingletonServices => {
193
+ const services = pikkuState(null, 'package', 'singletonServices')
194
+ if (!services) throw new Error('Singleton services not initialized')
195
+ return services
196
+ }
197
+
198
+ export const getCreateWireServices = (): CreateWireServices | undefined => {
199
+ return pikkuState(null, 'package', 'factories')?.createWireServices
200
+ }
201
+
185
202
  /**
186
- * Register service factories for an external package.
203
+ * Register service factories for an addon package.
187
204
  * These factories are used to create services when the package's functions are invoked.
188
205
  *
189
- * @param packageName - The package name (e.g., '@pikku/templates-function-external')
206
+ * @param packageName - The package name (e.g., '@pikku/templates-function-addon')
190
207
  * @param factories - The service factory functions
191
208
  */
192
209
  export const addPackageServiceFactories = (
@@ -1,11 +1,55 @@
1
- import { test, describe, before } from 'node:test'
1
+ import { test, describe, before, beforeEach } from 'node:test'
2
2
  import * as assert from 'assert'
3
- import { addSchema, coerceTopLevelDataFromSchema } from './schema.js'
3
+ import {
4
+ addSchema,
5
+ getSchema,
6
+ coerceTopLevelDataFromSchema,
7
+ validateSchema,
8
+ compileAllSchemas,
9
+ } from './schema.js'
10
+ import { resetPikkuState } from './pikku-state.js'
4
11
 
5
12
  describe('Schema', () => {
6
- describe('coerceQueryStringToArray', () => {
13
+ describe('addSchema and getSchema', () => {
14
+ beforeEach(() => {
15
+ resetPikkuState()
16
+ })
17
+
18
+ test('should add and retrieve a schema', () => {
19
+ const schema = { properties: { name: { type: 'string' } } }
20
+ addSchema('testAdd', schema)
21
+ const result = getSchema('testAdd')
22
+ assert.deepStrictEqual(result, schema)
23
+ })
24
+
25
+ test('should return undefined for non-existent schema', () => {
26
+ const result = getSchema('nonExistent')
27
+ assert.strictEqual(result, undefined)
28
+ })
29
+
30
+ test('should add schema for specific package', () => {
31
+ const schema = { properties: { id: { type: 'number' } } }
32
+ addSchema('pkgSchema', schema, '@addon/pkg')
33
+ const result = getSchema('pkgSchema', '@addon/pkg')
34
+ assert.deepStrictEqual(result, schema)
35
+ })
36
+
37
+ test('should not find package schema in main', () => {
38
+ addSchema('pkgOnly', { properties: {} }, '@addon/pkg')
39
+ const result = getSchema('pkgOnly', null)
40
+ assert.strictEqual(result, undefined)
41
+ })
42
+
43
+ test('should unwrap default export', () => {
44
+ const schema = { default: { properties: { x: { type: 'string' } } } }
45
+ addSchema('withDefault', schema)
46
+ const result = getSchema('withDefault')
47
+ assert.deepStrictEqual(result, { properties: { x: { type: 'string' } } })
48
+ })
49
+ })
50
+
51
+ describe('coerceTopLevelDataFromSchema', () => {
7
52
  before(() => {
8
- // Add schemas dynamically using addSchema
9
53
  addSchema('testSchema', {
10
54
  properties: {
11
55
  tags: { type: 'array' },
@@ -16,10 +60,16 @@ describe('Schema', () => {
16
60
 
17
61
  addSchema('booleanSchema', {
18
62
  properties: {
19
- isActive: true, // Invalid schema definition, but the function should handle it
63
+ isActive: true,
20
64
  tags: { type: 'array' },
21
65
  },
22
66
  })
67
+
68
+ addSchema('dateSchema', {
69
+ properties: {
70
+ createdAt: { type: 'string', format: 'date-time' },
71
+ },
72
+ })
23
73
  })
24
74
 
25
75
  test('should split a string into an array for properties of type array', () => {
@@ -51,7 +101,149 @@ describe('Schema', () => {
51
101
  const data = { tags: 'a,b,c', isActive: 'true' }
52
102
  coerceTopLevelDataFromSchema('booleanSchema', data)
53
103
  assert.deepStrictEqual(data.tags, ['a', 'b', 'c'])
54
- assert.strictEqual(data.isActive, 'true') // No coercion should happen
104
+ assert.strictEqual(data.isActive, 'true')
105
+ })
106
+
107
+ test('should coerce date-time strings to Date objects', () => {
108
+ const data = { createdAt: '2024-01-01T00:00:00Z' } as any
109
+ coerceTopLevelDataFromSchema('dateSchema', data)
110
+ assert.ok(data.createdAt instanceof Date)
111
+ })
112
+ })
113
+
114
+ describe('validateSchema', () => {
115
+ beforeEach(() => {
116
+ resetPikkuState()
117
+ })
118
+
119
+ test('should pass when no schema service provided', async () => {
120
+ const logger = {
121
+ info: () => {},
122
+ warn: () => {},
123
+ error: () => {},
124
+ debug: () => {},
125
+ } as any
126
+ await validateSchema(logger, undefined, 'some-schema', { data: 1 })
127
+ })
128
+
129
+ test('should warn when no schema name but data is passed', async () => {
130
+ let warningMsg = ''
131
+ const logger = {
132
+ info: () => {},
133
+ warn: (msg: string) => {
134
+ warningMsg = msg
135
+ },
136
+ error: () => {},
137
+ debug: () => {},
138
+ } as any
139
+ const schemaService = {
140
+ compileSchema: async () => {},
141
+ validateSchema: async () => {},
142
+ getSchemaNames: () => new Set<string>(),
143
+ }
144
+ await assert.rejects(
145
+ () => validateSchema(logger, schemaService, null, { key: 'value' }),
146
+ (err: any) => err.message === 'No data expected'
147
+ )
148
+ })
149
+
150
+ test('should return early when no schema name and empty data', async () => {
151
+ const logger = {
152
+ info: () => {},
153
+ warn: () => {},
154
+ error: () => {},
155
+ debug: () => {},
156
+ } as any
157
+ const schemaService = {
158
+ compileSchema: async () => {},
159
+ validateSchema: async () => {},
160
+ getSchemaNames: () => new Set<string>(),
161
+ }
162
+ await validateSchema(logger, schemaService, null, {})
163
+ })
164
+
165
+ test('should throw MissingSchemaError when schema not found', async () => {
166
+ const logger = {
167
+ info: () => {},
168
+ warn: () => {},
169
+ error: () => {},
170
+ debug: () => {},
171
+ } as any
172
+ const schemaService = {
173
+ compileSchema: async () => {},
174
+ validateSchema: async () => {},
175
+ getSchemaNames: () => new Set<string>(),
176
+ }
177
+ await assert.rejects(
178
+ () => validateSchema(logger, schemaService, 'nonExistent', { data: 1 }),
179
+ (err: any) => err.message.includes('not found')
180
+ )
181
+ })
182
+
183
+ test('should compile and validate schema when found', async () => {
184
+ addSchema('validSchema', { properties: { name: { type: 'string' } } })
185
+ const logger = {
186
+ info: () => {},
187
+ warn: () => {},
188
+ error: () => {},
189
+ debug: () => {},
190
+ } as any
191
+ let compiled = false
192
+ let validated = false
193
+ const schemaService = {
194
+ compileSchema: async () => {
195
+ compiled = true
196
+ },
197
+ validateSchema: async () => {
198
+ validated = true
199
+ },
200
+ getSchemaNames: () => new Set<string>(),
201
+ }
202
+ await validateSchema(logger, schemaService, 'validSchema', {
203
+ name: 'test',
204
+ })
205
+ assert.strictEqual(compiled, true)
206
+ assert.strictEqual(validated, true)
207
+ })
208
+ })
209
+
210
+ describe('compileAllSchemas', () => {
211
+ beforeEach(() => {
212
+ resetPikkuState()
213
+ })
214
+
215
+ test('should throw when no schema service available', () => {
216
+ const logger = {
217
+ info: () => {},
218
+ warn: () => {},
219
+ error: () => {},
220
+ debug: () => {},
221
+ } as any
222
+ assert.throws(() => compileAllSchemas(logger), {
223
+ message: 'SchemaService needs to be defined to load schemas',
224
+ })
225
+ })
226
+
227
+ test('should compile all schemas across packages', () => {
228
+ addSchema('schema1', { properties: { a: { type: 'string' } } })
229
+ addSchema('schema2', { properties: { b: { type: 'number' } } })
230
+
231
+ const compiled: string[] = []
232
+ const logger = {
233
+ info: () => {},
234
+ warn: () => {},
235
+ error: () => {},
236
+ debug: () => {},
237
+ } as any
238
+ const schemaService = {
239
+ compileSchema: (name: string, _schema: any) => {
240
+ compiled.push(name)
241
+ },
242
+ getSchemaNames: () => new Set(compiled),
243
+ }
244
+ compileAllSchemas(logger, schemaService as any)
245
+ assert.ok(compiled.includes('schema1'))
246
+ assert.ok(compiled.includes('schema2'))
55
247
  })
56
248
  })
57
249
  })
package/src/schema.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { Logger } from './services/logger.js'
2
- import { SchemaService } from './services/schema-service.js'
1
+ import type { Logger } from './services/logger.js'
2
+ import type { SchemaService } from './services/schema-service.js'
3
3
  import {
4
4
  MissingSchemaError,
5
5
  UnprocessableContentError,
6
6
  } from './errors/errors.js'
7
- import { pikkuState } from './pikku-state.js'
7
+ import { pikkuState, getAllPackageStates } from './pikku-state.js'
8
8
 
9
9
  const schemaKey = (name: string, packageName: string | null): string =>
10
10
  packageName ? `${packageName}:${name}` : name
@@ -13,7 +13,7 @@ const schemaKey = (name: string, packageName: string | null): string =>
13
13
  * Adds a schema to the schemas map for a specific package.
14
14
  * @param name - The name of the schema.
15
15
  * @param value - The schema value.
16
- * @param packageName - The package name (null for main package, '@scope/package' for external packages).
16
+ * @param packageName - The package name (null for main package, '@scope/package' for addon packages).
17
17
  * @ignore
18
18
  */
19
19
  export const addSchema = (
@@ -21,13 +21,14 @@ export const addSchema = (
21
21
  value: any,
22
22
  packageName: string | null = null
23
23
  ) => {
24
- pikkuState(packageName, 'misc', 'schemas').set(name, value)
24
+ const schema = value?.default ?? value
25
+ pikkuState(packageName, 'misc', 'schemas').set(name, schema)
25
26
  }
26
27
 
27
28
  /**
28
29
  * Retrieves a schema from the schemas map for a specific package.
29
30
  * @param name - The name of the schema.
30
- * @param packageName - The package name (null for main package, '@scope/package' for external packages).
31
+ * @param packageName - The package name (null for main package, '@scope/package' for addon packages).
31
32
  * @returns The schema value or undefined if not found.
32
33
  * @ignore
33
34
  */
@@ -46,10 +47,13 @@ export const compileAllSchemas = (
46
47
  logger: Logger,
47
48
  schemaService?: SchemaService
48
49
  ) => {
50
+ if (!schemaService) {
51
+ schemaService = pikkuState(null, 'package', 'singletonServices')?.schema
52
+ }
49
53
  if (!schemaService) {
50
54
  throw new Error('SchemaService needs to be defined to load schemas')
51
55
  }
52
- for (const [pkgName, packageState] of globalThis.pikkuState!) {
56
+ for (const [pkgName, packageState] of getAllPackageStates()) {
53
57
  const resolvedPkgName = pkgName === '__main__' ? null : pkgName
54
58
  for (const [name, schema] of packageState.misc.schemas) {
55
59
  schemaService.compileSchema(schemaKey(name, resolvedPkgName), schema)
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  AIMessage,
3
3
  AIAgentStep,
4
4
  AIAgentToolDef,
@@ -23,7 +23,19 @@ export type AIAgentRunnerResult = {
23
23
  usage: { inputTokens: number; outputTokens: number }
24
24
  }
25
25
 
26
+ export type AIAgentStepResult = {
27
+ text: string
28
+ object?: unknown
29
+ toolCalls: { toolCallId: string; toolName: string; args: unknown }[]
30
+ toolResults: { toolCallId: string; toolName: string; result: unknown }[]
31
+ usage: { inputTokens: number; outputTokens: number }
32
+ finishReason: 'stop' | 'tool-calls' | 'length' | 'error' | 'unknown'
33
+ }
34
+
26
35
  export interface AIAgentRunnerService {
27
- stream(params: AIAgentRunnerParams, channel: AIStreamChannel): Promise<void>
28
- run(params: AIAgentRunnerParams): Promise<AIAgentRunnerResult>
36
+ stream(
37
+ params: AIAgentRunnerParams,
38
+ channel: AIStreamChannel
39
+ ): Promise<AIAgentStepResult>
40
+ run(params: AIAgentRunnerParams): Promise<AIAgentStepResult>
29
41
  }
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  AgentRunState,
3
3
  PendingApproval,
4
4
  } from '../wirings/ai-agent/ai-agent.types.js'