@pikku/core 0.11.0 → 0.11.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 (184) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/dist/errors/error-handler.js +3 -3
  3. package/dist/errors/errors.d.ts +1 -1
  4. package/dist/errors/errors.js +3 -3
  5. package/dist/function/function-runner.d.ts +8 -8
  6. package/dist/function/function-runner.js +88 -23
  7. package/dist/function/functions.types.d.ts +104 -33
  8. package/dist/function/functions.types.js +50 -7
  9. package/dist/handle-error.d.ts +1 -1
  10. package/dist/handle-error.js +1 -1
  11. package/dist/index.d.ts +6 -2
  12. package/dist/index.js +5 -2
  13. package/dist/middleware/auth-apikey.d.ts +1 -1
  14. package/dist/middleware/auth-apikey.js +3 -3
  15. package/dist/middleware/auth-bearer.d.ts +1 -1
  16. package/dist/middleware/auth-bearer.js +3 -3
  17. package/dist/middleware/auth-cookie.d.ts +1 -1
  18. package/dist/middleware/auth-cookie.js +5 -5
  19. package/dist/middleware/timeout.d.ts +1 -1
  20. package/dist/middleware/timeout.js +3 -2
  21. package/dist/middleware-runner.d.ts +6 -20
  22. package/dist/middleware-runner.js +19 -20
  23. package/dist/permissions.d.ts +6 -89
  24. package/dist/permissions.js +24 -81
  25. package/dist/pikku-state.d.ts +32 -104
  26. package/dist/pikku-state.js +140 -66
  27. package/dist/schema.d.ts +8 -6
  28. package/dist/schema.js +25 -13
  29. package/dist/services/user-session-service.d.ts +7 -3
  30. package/dist/services/user-session-service.js +8 -1
  31. package/dist/services/workflow-service.d.ts +38 -0
  32. package/dist/services/workflow-service.js +1 -0
  33. package/dist/types/core.types.d.ts +40 -41
  34. package/dist/types/core.types.js +4 -15
  35. package/dist/types/state.types.d.ts +135 -0
  36. package/dist/types/state.types.js +1 -0
  37. package/dist/utils.d.ts +9 -1
  38. package/dist/utils.js +48 -3
  39. package/dist/wirings/channel/channel-common.js +2 -3
  40. package/dist/wirings/channel/channel-handler.d.ts +3 -2
  41. package/dist/wirings/channel/channel-handler.js +7 -10
  42. package/dist/wirings/channel/channel-runner.d.ts +2 -2
  43. package/dist/wirings/channel/channel-runner.js +5 -5
  44. package/dist/wirings/channel/channel.types.d.ts +10 -5
  45. package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
  46. package/dist/wirings/channel/local/local-channel-runner.js +19 -26
  47. package/dist/wirings/channel/log-channels.js +1 -1
  48. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
  49. package/dist/wirings/channel/serverless/serverless-channel-runner.js +43 -48
  50. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
  51. package/dist/wirings/cli/cli-runner.d.ts +5 -5
  52. package/dist/wirings/cli/cli-runner.js +20 -38
  53. package/dist/wirings/cli/cli.types.d.ts +16 -11
  54. package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
  55. package/dist/wirings/forge-node/forge-node.types.js +38 -0
  56. package/dist/wirings/forge-node/index.d.ts +1 -0
  57. package/dist/wirings/forge-node/index.js +1 -0
  58. package/dist/wirings/http/http-runner.d.ts +8 -8
  59. package/dist/wirings/http/http-runner.js +46 -51
  60. package/dist/wirings/http/http.types.d.ts +19 -11
  61. package/dist/wirings/http/log-http-routes.js +1 -1
  62. package/dist/wirings/http/routers/path-to-regex.js +2 -2
  63. package/dist/wirings/mcp/mcp-runner.d.ts +2 -2
  64. package/dist/wirings/mcp/mcp-runner.js +33 -40
  65. package/dist/wirings/mcp/mcp.types.d.ts +6 -0
  66. package/dist/wirings/queue/queue-runner.d.ts +3 -3
  67. package/dist/wirings/queue/queue-runner.js +13 -23
  68. package/dist/wirings/queue/queue.types.d.ts +4 -11
  69. package/dist/wirings/rpc/index.d.ts +1 -1
  70. package/dist/wirings/rpc/index.js +1 -1
  71. package/dist/wirings/rpc/rpc-runner.d.ts +17 -16
  72. package/dist/wirings/rpc/rpc-runner.js +98 -61
  73. package/dist/wirings/rpc/rpc-types.d.ts +7 -0
  74. package/dist/wirings/scheduler/log-schedulers.js +1 -1
  75. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -3
  76. package/dist/wirings/scheduler/scheduler-runner.js +18 -29
  77. package/dist/wirings/scheduler/scheduler.types.d.ts +3 -8
  78. package/dist/wirings/trigger/index.d.ts +2 -0
  79. package/dist/wirings/trigger/index.js +2 -0
  80. package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
  81. package/dist/wirings/trigger/trigger-runner.js +57 -0
  82. package/dist/wirings/trigger/trigger.types.d.ts +42 -0
  83. package/dist/wirings/trigger/trigger.types.js +1 -0
  84. package/dist/wirings/workflow/dsl/index.d.ts +5 -0
  85. package/dist/wirings/workflow/dsl/index.js +4 -0
  86. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
  87. package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
  88. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
  89. package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
  90. package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
  91. package/dist/wirings/workflow/graph/graph-node.js +58 -0
  92. package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
  93. package/dist/wirings/workflow/graph/graph-runner.js +452 -0
  94. package/dist/wirings/workflow/graph/index.d.ts +3 -0
  95. package/dist/wirings/workflow/graph/index.js +3 -0
  96. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
  97. package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
  98. package/dist/wirings/workflow/index.d.ts +7 -3
  99. package/dist/wirings/workflow/index.js +6 -3
  100. package/dist/wirings/workflow/pikku-workflow-service.d.ts +108 -10
  101. package/dist/wirings/workflow/pikku-workflow-service.js +274 -165
  102. package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
  103. package/dist/wirings/workflow/wire-workflow.js +53 -0
  104. package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
  105. package/dist/wirings/workflow/workflow-utils.js +66 -0
  106. package/dist/wirings/workflow/workflow.types.d.ts +135 -128
  107. package/package.json +11 -2
  108. package/src/errors/error-handler.ts +3 -3
  109. package/src/errors/errors.ts +3 -3
  110. package/src/factory-functions.test.ts +9 -36
  111. package/src/function/function-runner.test.ts +58 -69
  112. package/src/function/function-runner.ts +130 -37
  113. package/src/function/functions.types.ts +193 -54
  114. package/src/handle-error.ts +1 -1
  115. package/src/index.ts +10 -5
  116. package/src/middleware/auth-apikey.test.ts +360 -0
  117. package/src/middleware/auth-apikey.ts +3 -7
  118. package/src/middleware/auth-bearer.test.ts +447 -0
  119. package/src/middleware/auth-bearer.ts +27 -33
  120. package/src/middleware/auth-cookie.test.ts +525 -0
  121. package/src/middleware/auth-cookie.ts +6 -6
  122. package/src/middleware/timeout.ts +4 -2
  123. package/src/middleware-runner.test.ts +58 -127
  124. package/src/middleware-runner.ts +29 -25
  125. package/src/permissions.test.ts +68 -130
  126. package/src/permissions.ts +41 -100
  127. package/src/pikku-state.ts +156 -201
  128. package/src/schema.ts +42 -13
  129. package/src/services/user-session-service.ts +14 -4
  130. package/src/services/workflow-service.ts +74 -0
  131. package/src/types/core.types.ts +79 -58
  132. package/src/types/state.types.ts +195 -0
  133. package/src/utils.ts +59 -4
  134. package/src/wirings/channel/channel-common.ts +4 -7
  135. package/src/wirings/channel/channel-handler.ts +17 -23
  136. package/src/wirings/channel/channel-runner.ts +7 -7
  137. package/src/wirings/channel/channel.types.ts +14 -11
  138. package/src/wirings/channel/local/local-channel-runner.test.ts +8 -4
  139. package/src/wirings/channel/local/local-channel-runner.ts +23 -38
  140. package/src/wirings/channel/log-channels.ts +1 -1
  141. package/src/wirings/channel/serverless/serverless-channel-runner.ts +53 -79
  142. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
  143. package/src/wirings/cli/cli-runner.test.ts +26 -26
  144. package/src/wirings/cli/cli-runner.ts +34 -71
  145. package/src/wirings/cli/cli.types.ts +23 -16
  146. package/src/wirings/forge-node/forge-node.types.ts +135 -0
  147. package/src/wirings/forge-node/index.ts +1 -0
  148. package/src/wirings/http/http-runner.test.ts +10 -10
  149. package/src/wirings/http/http-runner.ts +56 -66
  150. package/src/wirings/http/http.types.ts +19 -14
  151. package/src/wirings/http/log-http-routes.ts +1 -1
  152. package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
  153. package/src/wirings/http/routers/path-to-regex.ts +2 -2
  154. package/src/wirings/mcp/mcp-runner.ts +44 -69
  155. package/src/wirings/mcp/mcp.types.ts +6 -0
  156. package/src/wirings/queue/queue-runner.test.ts +641 -0
  157. package/src/wirings/queue/queue-runner.ts +16 -38
  158. package/src/wirings/queue/queue.types.ts +4 -11
  159. package/src/wirings/rpc/index.ts +1 -1
  160. package/src/wirings/rpc/rpc-runner.ts +129 -77
  161. package/src/wirings/rpc/rpc-types.ts +8 -0
  162. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  163. package/src/wirings/scheduler/scheduler-runner.test.ts +627 -0
  164. package/src/wirings/scheduler/scheduler-runner.ts +29 -55
  165. package/src/wirings/scheduler/scheduler.types.ts +3 -9
  166. package/src/wirings/trigger/index.ts +2 -0
  167. package/src/wirings/trigger/trigger-runner.ts +96 -0
  168. package/src/wirings/trigger/trigger.types.ts +56 -0
  169. package/src/wirings/workflow/dsl/index.ts +30 -0
  170. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
  171. package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
  172. package/src/wirings/workflow/graph/graph-node.ts +227 -0
  173. package/src/wirings/workflow/graph/graph-runner.ts +694 -0
  174. package/src/wirings/workflow/graph/index.ts +3 -0
  175. package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
  176. package/src/wirings/workflow/index.ts +60 -12
  177. package/src/wirings/workflow/pikku-workflow-service.ts +401 -195
  178. package/src/wirings/workflow/wire-workflow.ts +94 -0
  179. package/src/wirings/workflow/workflow-utils.ts +120 -0
  180. package/src/wirings/workflow/workflow.types.ts +167 -188
  181. package/tsconfig.tsbuildinfo +1 -1
  182. package/dist/wirings/workflow/workflow-runner.d.ts +0 -35
  183. package/dist/wirings/workflow/workflow-runner.js +0 -68
  184. package/src/wirings/workflow/workflow-runner.ts +0 -85
@@ -3,11 +3,7 @@ import * as assert from 'node:assert'
3
3
  import { addFunction, runPikkuFunc } from './function-runner.js'
4
4
  import { addMiddleware, addPermission } from '../index.js'
5
5
  import { resetPikkuState, pikkuState } from '../pikku-state.js'
6
- import {
7
- CoreServices,
8
- CorePikkuMiddleware,
9
- PikkuWiringTypes,
10
- } from '../types/core.types.js'
6
+ import { CoreServices, CorePikkuMiddleware } from '../types/core.types.js'
11
7
  import { CorePermissionGroup } from './functions.types.js'
12
8
 
13
9
  beforeEach(() => {
@@ -25,7 +21,7 @@ const addTestFunction = (funcName: string, funcConfig: any) => {
25
21
  const permissions = funcConfig.tags
26
22
  ? funcConfig.tags.map((tag: string) => ({ type: 'tag' as const, tag }))
27
23
  : undefined
28
- pikkuState('function', 'meta')[funcName] = {
24
+ pikkuState(null, 'function', 'meta')[funcName] = {
29
25
  pikkuFuncName: funcName,
30
26
  inputSchemaName: null,
31
27
  outputSchemaName: null,
@@ -51,7 +47,7 @@ describe('runPikkuFunc - Integration Tests', () => {
51
47
  test('should execute middleware in correct order: wiringTags → wiringMiddleware → funcTags → funcMiddleware', async () => {
52
48
  const executionOrder: string[] = []
53
49
  const createMiddleware = (name: string): CorePikkuMiddleware => {
54
- return async (services, interaction, next) => {
50
+ return async (services, wire, next) => {
55
51
  executionOrder.push(name)
56
52
  await next()
57
53
  }
@@ -71,7 +67,7 @@ describe('runPikkuFunc - Integration Tests', () => {
71
67
  })
72
68
 
73
69
  const result = await runPikkuFunc(
74
- PikkuWiringTypes.rpc,
70
+ 'rpc',
75
71
  Math.random().toString(),
76
72
  'testFunc',
77
73
  {
@@ -81,7 +77,7 @@ describe('runPikkuFunc - Integration Tests', () => {
81
77
  wireMiddleware: [createMiddleware('wiringMiddleware')],
82
78
  inheritedMiddleware: [{ type: 'tag', tag: 'wiringTag' }],
83
79
  auth: false,
84
- interaction: {},
80
+ wire: {},
85
81
  }
86
82
  )
87
83
 
@@ -141,7 +137,7 @@ describe('runPikkuFunc - Integration Tests', () => {
141
137
  })
142
138
 
143
139
  const result = await runPikkuFunc(
144
- PikkuWiringTypes.rpc,
140
+ 'rpc',
145
141
  Math.random().toString(),
146
142
  'testFunc',
147
143
  {
@@ -151,7 +147,7 @@ describe('runPikkuFunc - Integration Tests', () => {
151
147
  wirePermissions: wiringPermissions,
152
148
  tags: ['wiringTag'],
153
149
  auth: false,
154
- interaction: {},
150
+ wire: {},
155
151
  }
156
152
  )
157
153
 
@@ -176,13 +172,13 @@ describe('runPikkuFunc - Integration Tests', () => {
176
172
  })
177
173
 
178
174
  await assert.rejects(
179
- runPikkuFunc(PikkuWiringTypes.rpc, Math.random().toString(), 'testFunc', {
175
+ runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
180
176
  singletonServices: mockSingletonServices,
181
177
  getAllServices: () => mockServices,
182
178
  data: () => ({}),
183
179
  tags: ['wiringTag'],
184
180
  auth: false,
185
- interaction: {},
181
+ wire: {},
186
182
  }),
187
183
  {
188
184
  message: 'Permission denied',
@@ -200,13 +196,13 @@ describe('runPikkuFunc - Integration Tests', () => {
200
196
  })
201
197
 
202
198
  await assert.rejects(
203
- runPikkuFunc(PikkuWiringTypes.rpc, Math.random().toString(), 'testFunc', {
199
+ runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
204
200
  singletonServices: mockSingletonServices,
205
201
  getAllServices: () => mockServices,
206
202
  data: () => ({}),
207
203
  wirePermissions: wiringPermissions,
208
204
  auth: false,
209
- interaction: {},
205
+ wire: {},
210
206
  }),
211
207
  {
212
208
  message: 'Permission denied',
@@ -225,12 +221,12 @@ describe('runPikkuFunc - Integration Tests', () => {
225
221
  })
226
222
 
227
223
  await assert.rejects(
228
- runPikkuFunc(PikkuWiringTypes.rpc, Math.random().toString(), 'testFunc', {
224
+ runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
229
225
  singletonServices: mockSingletonServices,
230
226
  getAllServices: () => mockServices,
231
227
  data: () => ({}),
232
228
  auth: false,
233
- interaction: {},
229
+ wire: {},
234
230
  }),
235
231
  {
236
232
  message: 'Permission denied',
@@ -249,12 +245,12 @@ describe('runPikkuFunc - Integration Tests', () => {
249
245
  })
250
246
 
251
247
  await assert.rejects(
252
- runPikkuFunc(PikkuWiringTypes.rpc, Math.random().toString(), 'testFunc', {
248
+ runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
253
249
  singletonServices: mockSingletonServices,
254
250
  getAllServices: () => mockServices,
255
251
  data: () => ({}),
256
252
  auth: false,
257
- interaction: {},
253
+ wire: {},
258
254
  }),
259
255
  {
260
256
  message: 'Permission denied',
@@ -267,7 +263,7 @@ describe('runPikkuFunc - Integration Tests', () => {
267
263
 
268
264
  const duplicatedMiddleware: CorePikkuMiddleware = async (
269
265
  services,
270
- interaction,
266
+ wire,
271
267
  next
272
268
  ) => {
273
269
  executionCount++
@@ -283,18 +279,13 @@ describe('runPikkuFunc - Integration Tests', () => {
283
279
  tags: ['testTag'], // Same middleware via tag
284
280
  })
285
281
 
286
- await runPikkuFunc(
287
- PikkuWiringTypes.rpc,
288
- Math.random().toString(),
289
- 'testFunc',
290
- {
291
- singletonServices: mockSingletonServices,
292
- getAllServices: () => mockServices,
293
- data: () => ({}),
294
- auth: false,
295
- interaction: {},
296
- }
297
- )
282
+ await runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
283
+ singletonServices: mockSingletonServices,
284
+ getAllServices: () => mockServices,
285
+ data: () => ({}),
286
+ auth: false,
287
+ wire: {},
288
+ })
298
289
 
299
290
  // Should only execute once due to deduplication
300
291
  assert.equal(executionCount, 1)
@@ -336,7 +327,7 @@ describe('runPikkuFunc - Integration Tests', () => {
336
327
  })
337
328
 
338
329
  const result = await runPikkuFunc(
339
- PikkuWiringTypes.rpc,
330
+ 'rpc',
340
331
  Math.random().toString(),
341
332
  'testFunc',
342
333
  {
@@ -344,7 +335,7 @@ describe('runPikkuFunc - Integration Tests', () => {
344
335
  getAllServices: () => mockServices,
345
336
  data: () => ({}),
346
337
  auth: false,
347
- interaction: {},
338
+ wire: {},
348
339
  }
349
340
  )
350
341
 
@@ -364,7 +355,7 @@ describe('runPikkuFunc - Integration Tests', () => {
364
355
  })
365
356
 
366
357
  const result = await runPikkuFunc(
367
- PikkuWiringTypes.rpc,
358
+ 'rpc',
368
359
  Math.random().toString(),
369
360
  'simpleFunc',
370
361
  {
@@ -372,7 +363,7 @@ describe('runPikkuFunc - Integration Tests', () => {
372
363
  getAllServices: () => mockServices,
373
364
  data: () => ({}),
374
365
  auth: false,
375
- interaction: {},
366
+ wire: {},
376
367
  }
377
368
  )
378
369
 
@@ -384,7 +375,7 @@ describe('runPikkuFunc - Integration Tests', () => {
384
375
 
385
376
  const wiringMiddleware: CorePikkuMiddleware = async (
386
377
  services,
387
- interaction,
378
+ wire,
388
379
  next
389
380
  ) => {
390
381
  executionOrder.push('wiringMiddleware')
@@ -408,7 +399,7 @@ describe('runPikkuFunc - Integration Tests', () => {
408
399
  })
409
400
 
410
401
  const result = await runPikkuFunc(
411
- PikkuWiringTypes.rpc,
402
+ 'rpc',
412
403
  Math.random().toString(),
413
404
  'testFunc',
414
405
  {
@@ -418,7 +409,7 @@ describe('runPikkuFunc - Integration Tests', () => {
418
409
  wireMiddleware: [wiringMiddleware],
419
410
  wirePermissions: wiringPermissions,
420
411
  auth: false,
421
- interaction: {},
412
+ wire: {},
422
413
  }
423
414
  )
424
415
 
@@ -436,7 +427,7 @@ describe('runPikkuFunc - Integration Tests', () => {
436
427
 
437
428
  const funcMiddleware: CorePikkuMiddleware = async (
438
429
  services,
439
- interaction,
430
+ wire,
440
431
  next
441
432
  ) => {
442
433
  executionOrder.push('funcMiddleware')
@@ -462,7 +453,7 @@ describe('runPikkuFunc - Integration Tests', () => {
462
453
  })
463
454
 
464
455
  const result = await runPikkuFunc(
465
- PikkuWiringTypes.rpc,
456
+ 'rpc',
466
457
  Math.random().toString(),
467
458
  'testFunc',
468
459
  {
@@ -470,7 +461,7 @@ describe('runPikkuFunc - Integration Tests', () => {
470
461
  getAllServices: () => mockServices,
471
462
  data: () => ({}),
472
463
  auth: false,
473
- interaction: {},
464
+ wire: {},
474
465
  }
475
466
  )
476
467
 
@@ -486,69 +477,67 @@ describe('runPikkuFunc - Integration Tests', () => {
486
477
  test('should pass correct parameters to function', async () => {
487
478
  let receivedServices: any
488
479
  let receivedData: any
489
- let receivedSession: any
480
+ let receivedWire: any
490
481
 
491
482
  const testData = { test: 'data' }
492
- const testSession = { userId: 'test-user' }
493
483
 
494
484
  addTestFunction('testFunc', {
495
- func: async (services, data, session) => {
485
+ func: async (services, data, wire) => {
496
486
  receivedServices = services
497
487
  receivedData = data
498
- receivedSession = session
488
+ receivedWire = wire
499
489
  return 'success'
500
490
  },
501
491
  })
502
492
 
503
- await runPikkuFunc(
504
- PikkuWiringTypes.rpc,
505
- Math.random().toString(),
506
- 'testFunc',
507
- {
508
- singletonServices: mockSingletonServices,
509
- getAllServices: () => mockServices,
510
- data: () => testData,
511
- userSession: { get: () => testSession, set: () => {} } as any,
512
- auth: false,
513
- interaction: {},
514
- }
515
- )
493
+ await runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
494
+ singletonServices: mockServices,
495
+ data: () => testData,
496
+ auth: false,
497
+ wire: { rpc: {} },
498
+ })
516
499
 
517
- assert.equal(receivedServices, mockServices)
500
+ assert.deepEqual(receivedServices, mockServices)
518
501
  assert.equal(receivedData, testData)
519
- assert.equal(receivedSession, testSession)
502
+ // Check that wire has rpc service and session
503
+ assert.ok(receivedWire.rpc)
504
+ assert.equal(receivedWire.session, undefined)
520
505
  })
521
506
 
522
- test('should handle async getAllServices function', async () => {
507
+ test('should handle async createWireServices function', async () => {
523
508
  let servicesProvided: any
509
+ const wireServices = { customService: 'value' }
524
510
 
525
511
  addTestFunction('testFunc', {
526
- func: async (services) => {
512
+ func: async (services, data, wire) => {
527
513
  servicesProvided = services
528
514
  return 'success'
529
515
  },
530
516
  })
531
517
 
532
- const asyncGetServices = async () => {
518
+ const asyncCreateWireServices = async () => {
533
519
  // Simulate async service creation
534
520
  await new Promise((resolve) => setTimeout(resolve, 1))
535
- return mockServices
521
+ return wireServices
536
522
  }
537
523
 
538
524
  const result = await runPikkuFunc(
539
- PikkuWiringTypes.rpc,
525
+ 'rpc',
540
526
  Math.random().toString(),
541
527
  'testFunc',
542
528
  {
543
529
  singletonServices: mockSingletonServices,
544
- getAllServices: asyncGetServices,
530
+ createWireServices: asyncCreateWireServices,
545
531
  data: () => ({}),
546
532
  auth: false,
547
- interaction: {},
533
+ wire: {},
548
534
  }
549
535
  )
550
536
 
551
537
  assert.equal(result, 'success')
552
- assert.equal(servicesProvided, mockServices)
538
+ assert.deepEqual(servicesProvided, {
539
+ ...mockSingletonServices,
540
+ ...wireServices,
541
+ })
553
542
  })
554
543
  })
@@ -7,37 +7,94 @@ import {
7
7
  CoreUserSession,
8
8
  CorePikkuMiddleware,
9
9
  PikkuWiringTypes,
10
- CoreSingletonServices,
11
- PikkuInteraction,
10
+ PikkuWire,
12
11
  MiddlewareMetadata,
13
12
  PermissionMetadata,
13
+ CoreSingletonServices,
14
+ CreateWireServices,
15
+ CoreConfig,
14
16
  } from '../types/core.types.js'
15
17
  import {
16
18
  CorePermissionGroup,
17
19
  CorePikkuFunctionConfig,
18
20
  CorePikkuPermission,
19
21
  } from './functions.types.js'
20
- import { UserSessionService } from '../services/user-session-service.js'
22
+ import { SessionService } from '../services/user-session-service.js'
21
23
  import { ForbiddenError } from '../errors/errors.js'
24
+ import { rpcService } from '../wirings/rpc/rpc-runner.js'
25
+ import { closeWireServices } from '../utils.js'
26
+
27
+ /**
28
+ * Get or create singleton services for an external package.
29
+ * Services are cached in pikkuState to avoid recreation on each call.
30
+ *
31
+ * @param packageName - The external package name
32
+ * @param parentServices - The parent/caller's singleton services (used as base)
33
+ * @returns The package's singleton services
34
+ */
35
+ const getOrCreatePackageSingletonServices = async (
36
+ packageName: string,
37
+ parentServices: CoreSingletonServices
38
+ ): Promise<CoreSingletonServices> => {
39
+ // Check if we already have cached singleton services for this package
40
+ const cachedServices = pikkuState(packageName, 'package', 'singletonServices')
41
+ if (cachedServices) {
42
+ return cachedServices
43
+ }
44
+
45
+ // Get the package's service factories
46
+ const factories = pikkuState(packageName, 'package', 'factories')
47
+ if (!factories || !factories.createSingletonServices) {
48
+ // No factories registered, use parent services
49
+ return parentServices
50
+ }
51
+
52
+ // Create config for the package (use parent config if no factory)
53
+ let config: CoreConfig = parentServices.config
54
+ if (factories.createConfig) {
55
+ config = await factories.createConfig(parentServices.variables)
56
+ }
57
+
58
+ // Create singleton services for the package, passing parent services as existing
59
+ const packageServices = await factories.createSingletonServices(
60
+ config,
61
+ parentServices
62
+ )
63
+
64
+ // Cache the services
65
+ pikkuState(packageName, 'package', 'singletonServices', packageServices)
66
+
67
+ return packageServices
68
+ }
22
69
 
23
70
  export const addFunction = (
24
71
  funcName: string,
25
- funcConfig: CorePikkuFunctionConfig<any, any>
72
+ funcConfig: CorePikkuFunctionConfig<any, any>,
73
+ packageName: string | null = null
26
74
  ) => {
27
- pikkuState('function', 'functions').set(funcName, funcConfig)
75
+ pikkuState(packageName, 'function', 'functions').set(funcName, funcConfig)
28
76
  }
29
77
 
30
78
  export const runPikkuFuncDirectly = async <In, Out>(
31
79
  funcName: string,
32
80
  allServices: CoreServices,
81
+ wire: PikkuWire,
33
82
  data: In,
34
- session?: CoreUserSession
83
+ userSession?: SessionService<CoreUserSession>,
84
+ packageName: string | null = null
35
85
  ) => {
36
- const funcConfig = pikkuState('function', 'functions').get(funcName)
86
+ const funcConfig = pikkuState(packageName, 'function', 'functions').get(
87
+ funcName
88
+ )
37
89
  if (!funcConfig) {
38
90
  throw new Error(`Function not found: ${funcName}`)
39
91
  }
40
- return (await funcConfig.func(allServices, data, session!)) as Out
92
+ // Inject session into wire
93
+ const wireWithSession = {
94
+ ...wire,
95
+ session: userSession,
96
+ }
97
+ return (await funcConfig.func(allServices, data, wireWithSession)) as Out
41
98
  }
42
99
 
43
100
  export const runPikkuFunc = async <In = any, Out = any>(
@@ -45,10 +102,9 @@ export const runPikkuFunc = async <In = any, Out = any>(
45
102
  wireId: string,
46
103
  funcName: string,
47
104
  {
48
- getAllServices,
49
105
  singletonServices,
106
+ createWireServices,
50
107
  data,
51
- userSession,
52
108
  auth: wiringAuth,
53
109
  inheritedMiddleware,
54
110
  wireMiddleware,
@@ -56,13 +112,11 @@ export const runPikkuFunc = async <In = any, Out = any>(
56
112
  wirePermissions,
57
113
  coerceDataFromSchema,
58
114
  tags = [],
59
- interaction,
115
+ wire,
116
+ packageName = null,
60
117
  }: {
61
118
  singletonServices: CoreSingletonServices
62
- getAllServices: (
63
- session?: CoreUserSession
64
- ) => Promise<CoreServices> | CoreServices
65
- userSession?: UserSessionService<CoreUserSession>
119
+ createWireServices?: CreateWireServices
66
120
  data: () => Promise<In> | In
67
121
  auth?: boolean
68
122
  inheritedMiddleware?: MiddlewareMetadata[]
@@ -71,18 +125,36 @@ export const runPikkuFunc = async <In = any, Out = any>(
71
125
  wirePermissions?: CorePermissionGroup | CorePikkuPermission[]
72
126
  coerceDataFromSchema?: boolean
73
127
  tags?: string[]
74
- interaction: PikkuInteraction
128
+ wire: PikkuWire
129
+ packageName?: string | null
75
130
  }
76
131
  ): Promise<Out> => {
77
- const funcConfig = pikkuState('function', 'functions').get(funcName)
132
+ const funcConfig = pikkuState(packageName, 'function', 'functions').get(
133
+ funcName
134
+ )
78
135
  if (!funcConfig) {
79
136
  throw new Error(`Function not found: ${funcName}`)
80
137
  }
81
- const funcMeta = pikkuState('function', 'meta')[funcName]
138
+ const allMeta = pikkuState(packageName, 'function', 'meta')
139
+ const funcMeta = allMeta[funcName]
82
140
  if (!funcMeta) {
83
141
  throw new Error(`Function meta not found: ${funcName}`)
84
142
  }
85
143
 
144
+ // For external packages, get or create their singleton services
145
+ const resolvedSingletonServices = packageName
146
+ ? await getOrCreatePackageSingletonServices(packageName, singletonServices)
147
+ : singletonServices
148
+
149
+ // Get the package's createWireServices if available
150
+ let resolvedCreateWireServices = createWireServices
151
+ if (packageName) {
152
+ const factories = pikkuState(packageName, 'package', 'factories')
153
+ if (factories?.createWireServices) {
154
+ resolvedCreateWireServices = factories.createWireServices
155
+ }
156
+ }
157
+
86
158
  // Convert tags to PermissionMetadata and merge with inheritedPermissions
87
159
  const mergedInheritedPermissions: PermissionMetadata[] = [
88
160
  ...(inheritedPermissions || []),
@@ -91,16 +163,23 @@ export const runPikkuFunc = async <In = any, Out = any>(
91
163
 
92
164
  // Helper function to run permissions and execute the function
93
165
  const executeFunction = async () => {
94
- const session = await userSession?.get()
166
+ const initialSession = wire.session?.freezeInitial()
167
+
168
+ const wireWithInitialSession: PikkuWire = {
169
+ ...wire,
170
+ initialSession,
171
+ }
172
+
95
173
  if (wiringAuth === true || funcConfig.auth === true) {
96
174
  // This means it was explicitly enabled in either wiring or function and has to be respected
97
- if (!session) {
175
+ if (!initialSession) {
98
176
  throw new ForbiddenError('Authentication required')
99
177
  }
100
178
  }
101
179
  if (wiringAuth === undefined && funcConfig.auth === undefined) {
102
180
  // We always default to requiring auth unless explicitly disabled
103
- if (!session) {
181
+ if (!initialSession) {
182
+ // TODO: Critical, we need to figure out how to make this work with different wirings
104
183
  // throw new ForbiddenError('Authentication required')
105
184
  }
106
185
  }
@@ -113,48 +192,62 @@ export const runPikkuFunc = async <In = any, Out = any>(
113
192
  if (inputSchemaName) {
114
193
  // Validate request data against the defined schema, if any
115
194
  await validateSchema(
116
- singletonServices.logger,
117
- singletonServices.schema,
195
+ resolvedSingletonServices.logger,
196
+ resolvedSingletonServices.schema,
118
197
  inputSchemaName,
119
- actualData
198
+ actualData,
199
+ packageName
120
200
  )
121
201
  // Coerce (top level) query string parameters or date objects if specified by the schema
122
202
  if (coerceDataFromSchema) {
123
- coerceTopLevelDataFromSchema(inputSchemaName, actualData)
203
+ coerceTopLevelDataFromSchema(inputSchemaName, actualData, packageName)
124
204
  }
125
205
  }
126
206
 
127
- const allServices = await getAllServices(session)
128
-
129
- // Run permissions check with combined permissions: inheritedPermissions (including tags) → wirePermissions → funcPermissions
130
207
  await runPermissions(wireType, wireId, {
131
208
  wireInheritedPermissions: mergedInheritedPermissions,
132
209
  wirePermissions: wirePermissions,
133
210
  funcInheritedPermissions: funcMeta.permissions,
134
211
  funcPermissions: funcConfig.permissions,
135
- allServices,
212
+ services: resolvedSingletonServices,
213
+ wire: { ...wireWithInitialSession, rpc: undefined } as any,
136
214
  data: actualData,
137
- session,
215
+ packageName,
138
216
  })
139
217
 
140
- return await funcConfig.func(allServices, actualData, session!)
218
+ const wireServices = await resolvedCreateWireServices?.(
219
+ resolvedSingletonServices,
220
+ wireWithInitialSession
221
+ )
222
+ try {
223
+ const services = { ...resolvedSingletonServices, ...wireServices }
224
+ const rpc = rpcService.getContextRPCService(
225
+ services,
226
+ wireWithInitialSession
227
+ )
228
+ return await funcConfig.func(services, actualData, {
229
+ ...wireWithInitialSession,
230
+ rpc,
231
+ })
232
+ } finally {
233
+ if (wireServices) {
234
+ await closeWireServices(resolvedSingletonServices.logger, wireServices)
235
+ }
236
+ }
141
237
  }
142
238
 
143
- // Combine all middleware: inheritedMiddleware → wireMiddleware → funcMiddleware
144
239
  const allMiddleware = combineMiddleware(wireType, wireId, {
145
240
  wireInheritedMiddleware: inheritedMiddleware,
146
241
  wireMiddleware,
147
242
  funcInheritedMiddleware: funcMeta.middleware,
148
243
  funcMiddleware: funcConfig.middleware,
244
+ packageName,
149
245
  })
150
246
 
151
247
  if (allMiddleware.length > 0) {
152
248
  return (await runMiddleware<CorePikkuMiddleware>(
153
- {
154
- ...singletonServices,
155
- userSession,
156
- },
157
- interaction,
249
+ resolvedSingletonServices,
250
+ wire,
158
251
  allMiddleware,
159
252
  executeFunction
160
253
  )) as Out