@pikku/core 0.10.2 → 0.11.1

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 (138) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/errors/errors.d.ts +1 -1
  3. package/dist/errors/errors.js +3 -3
  4. package/dist/function/function-runner.d.ts +6 -7
  5. package/dist/function/function-runner.js +35 -16
  6. package/dist/function/functions.types.d.ts +23 -30
  7. package/dist/function/functions.types.js +9 -6
  8. package/dist/handle-error.d.ts +1 -1
  9. package/dist/handle-error.js +1 -1
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +2 -0
  12. package/dist/middleware/auth-apikey.d.ts +1 -0
  13. package/dist/middleware/auth-apikey.js +3 -3
  14. package/dist/middleware/auth-bearer.d.ts +1 -0
  15. package/dist/middleware/auth-bearer.js +3 -3
  16. package/dist/middleware/auth-cookie.d.ts +1 -0
  17. package/dist/middleware/auth-cookie.js +5 -5
  18. package/dist/middleware/timeout.d.ts +1 -0
  19. package/dist/middleware/timeout.js +3 -2
  20. package/dist/middleware-runner.d.ts +3 -6
  21. package/dist/middleware-runner.js +11 -11
  22. package/dist/permissions.d.ts +6 -6
  23. package/dist/permissions.js +15 -15
  24. package/dist/pikku-state.d.ts +7 -2
  25. package/dist/pikku-state.js +4 -0
  26. package/dist/services/index.d.ts +1 -0
  27. package/dist/services/index.js +1 -0
  28. package/dist/services/scheduler-service.d.ts +63 -0
  29. package/dist/services/scheduler-service.js +6 -0
  30. package/dist/services/user-session-service.d.ts +7 -3
  31. package/dist/services/user-session-service.js +8 -1
  32. package/dist/time-utils.d.ts +14 -0
  33. package/dist/time-utils.js +62 -0
  34. package/dist/types/core.types.d.ts +48 -35
  35. package/dist/types/core.types.js +3 -13
  36. package/dist/utils.d.ts +1 -1
  37. package/dist/utils.js +3 -3
  38. package/dist/wirings/channel/channel-common.js +2 -3
  39. package/dist/wirings/channel/channel-handler.d.ts +3 -2
  40. package/dist/wirings/channel/channel-handler.js +6 -9
  41. package/dist/wirings/channel/channel-runner.d.ts +2 -2
  42. package/dist/wirings/channel/channel.types.d.ts +10 -5
  43. package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
  44. package/dist/wirings/channel/local/local-channel-runner.js +19 -26
  45. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
  46. package/dist/wirings/channel/serverless/serverless-channel-runner.js +41 -46
  47. package/dist/wirings/cli/channel/cli-channel-runner.js +1 -1
  48. package/dist/wirings/cli/cli-runner.d.ts +5 -5
  49. package/dist/wirings/cli/cli-runner.js +11 -29
  50. package/dist/wirings/cli/cli.types.d.ts +15 -11
  51. package/dist/wirings/http/http-runner.d.ts +6 -6
  52. package/dist/wirings/http/http-runner.js +25 -39
  53. package/dist/wirings/http/http.types.d.ts +5 -10
  54. package/dist/wirings/mcp/mcp-runner.d.ts +2 -2
  55. package/dist/wirings/mcp/mcp-runner.js +12 -19
  56. package/dist/wirings/mcp/mcp.types.d.ts +6 -0
  57. package/dist/wirings/queue/queue-runner.d.ts +3 -3
  58. package/dist/wirings/queue/queue-runner.js +7 -14
  59. package/dist/wirings/queue/queue.types.d.ts +4 -13
  60. package/dist/wirings/rpc/index.d.ts +1 -1
  61. package/dist/wirings/rpc/index.js +1 -1
  62. package/dist/wirings/rpc/rpc-runner.d.ts +13 -7
  63. package/dist/wirings/rpc/rpc-runner.js +50 -26
  64. package/dist/wirings/rpc/rpc-types.d.ts +1 -0
  65. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -3
  66. package/dist/wirings/scheduler/scheduler-runner.js +13 -24
  67. package/dist/wirings/scheduler/scheduler.types.d.ts +3 -8
  68. package/dist/wirings/workflow/index.d.ts +15 -0
  69. package/dist/wirings/workflow/index.js +14 -0
  70. package/dist/wirings/workflow/pikku-workflow-service.d.ts +160 -0
  71. package/dist/wirings/workflow/pikku-workflow-service.js +430 -0
  72. package/dist/wirings/workflow/workflow-runner.d.ts +34 -0
  73. package/dist/wirings/workflow/workflow-runner.js +65 -0
  74. package/dist/wirings/workflow/workflow.types.d.ts +332 -0
  75. package/dist/wirings/workflow/workflow.types.js +1 -0
  76. package/package.json +3 -4
  77. package/src/errors/errors.ts +3 -3
  78. package/src/factory-functions.test.ts +9 -36
  79. package/src/function/function-runner.test.ts +57 -68
  80. package/src/function/function-runner.ts +51 -28
  81. package/src/function/function-runner.ts.bak +188 -0
  82. package/src/function/functions.types.ts +69 -51
  83. package/src/handle-error.ts +1 -1
  84. package/src/index.ts +2 -0
  85. package/src/middleware/auth-apikey.test.ts +360 -0
  86. package/src/middleware/auth-apikey.ts +3 -7
  87. package/src/middleware/auth-bearer.test.ts +447 -0
  88. package/src/middleware/auth-bearer.ts +27 -33
  89. package/src/middleware/auth-cookie.test.ts +525 -0
  90. package/src/middleware/auth-cookie.ts +6 -6
  91. package/src/middleware/timeout.ts +4 -2
  92. package/src/middleware-runner.test.ts +58 -127
  93. package/src/middleware-runner.ts +13 -15
  94. package/src/permissions.test.ts +41 -45
  95. package/src/permissions.ts +21 -20
  96. package/src/pikku-state.ts +14 -2
  97. package/src/services/index.ts +1 -0
  98. package/src/services/scheduler-service.ts +76 -0
  99. package/src/services/user-session-service.ts +14 -4
  100. package/src/time-utils.ts +75 -0
  101. package/src/types/core.types.ts +92 -51
  102. package/src/utils.ts +4 -4
  103. package/src/wirings/channel/channel-common.ts +4 -7
  104. package/src/wirings/channel/channel-handler.ts +16 -22
  105. package/src/wirings/channel/channel-runner.ts +2 -2
  106. package/src/wirings/channel/channel.types.ts +14 -11
  107. package/src/wirings/channel/local/local-channel-runner.test.ts +5 -3
  108. package/src/wirings/channel/local/local-channel-runner.ts +23 -38
  109. package/src/wirings/channel/serverless/serverless-channel-runner.ts +51 -77
  110. package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
  111. package/src/wirings/cli/cli-runner.test.ts +7 -7
  112. package/src/wirings/cli/cli-runner.ts +25 -63
  113. package/src/wirings/cli/cli.types.ts +22 -16
  114. package/src/wirings/http/http-runner.test.ts +8 -8
  115. package/src/wirings/http/http-runner.ts +29 -56
  116. package/src/wirings/http/http.types.ts +5 -14
  117. package/src/wirings/mcp/mcp-runner.ts +23 -48
  118. package/src/wirings/mcp/mcp.types.ts +6 -0
  119. package/src/wirings/queue/queue-runner.test.ts +641 -0
  120. package/src/wirings/queue/queue-runner.ts +10 -24
  121. package/src/wirings/queue/queue.types.ts +5 -15
  122. package/src/wirings/rpc/index.ts +1 -1
  123. package/src/wirings/rpc/rpc-runner.ts +71 -32
  124. package/src/wirings/rpc/rpc-types.ts +1 -0
  125. package/src/wirings/scheduler/scheduler-runner.test.ts +627 -0
  126. package/src/wirings/scheduler/scheduler-runner.ts +24 -50
  127. package/src/wirings/scheduler/scheduler.types.ts +3 -9
  128. package/src/wirings/workflow/index.ts +43 -0
  129. package/src/wirings/workflow/pikku-workflow-service.ts +746 -0
  130. package/src/wirings/workflow/workflow-runner.ts +72 -0
  131. package/src/wirings/workflow/workflow.types.ts +422 -0
  132. package/tsconfig.tsbuildinfo +1 -1
  133. package/dist/services/file-channel-store.d.ts +0 -19
  134. package/dist/services/file-channel-store.js +0 -69
  135. package/dist/services/file-eventhub-store.d.ts +0 -17
  136. package/dist/services/file-eventhub-store.js +0 -71
  137. package/src/services/file-channel-store.ts +0 -86
  138. package/src/services/file-eventhub-store.ts +0 -90
@@ -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(() => {
@@ -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,18 +7,21 @@ 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,
14
15
  } from '../types/core.types.js'
15
16
  import {
16
17
  CorePermissionGroup,
17
18
  CorePikkuFunctionConfig,
18
19
  CorePikkuPermission,
19
20
  } from './functions.types.js'
20
- import { UserSessionService } from '../services/user-session-service.js'
21
+ import { SessionService } from '../services/user-session-service.js'
21
22
  import { ForbiddenError } from '../errors/errors.js'
23
+ import { rpcService } from '../wirings/rpc/rpc-runner.js'
24
+ import { closeWireServices } from '../utils.js'
22
25
 
23
26
  export const addFunction = (
24
27
  funcName: string,
@@ -30,14 +33,20 @@ export const addFunction = (
30
33
  export const runPikkuFuncDirectly = async <In, Out>(
31
34
  funcName: string,
32
35
  allServices: CoreServices,
36
+ wire: PikkuWire,
33
37
  data: In,
34
- session?: CoreUserSession
38
+ userSession?: SessionService<CoreUserSession>
35
39
  ) => {
36
40
  const funcConfig = pikkuState('function', 'functions').get(funcName)
37
41
  if (!funcConfig) {
38
42
  throw new Error(`Function not found: ${funcName}`)
39
43
  }
40
- return (await funcConfig.func(allServices, data, session!)) as Out
44
+ // Inject session into wire
45
+ const wireWithSession = {
46
+ ...wire,
47
+ session: userSession,
48
+ }
49
+ return (await funcConfig.func(allServices, data, wireWithSession)) as Out
41
50
  }
42
51
 
43
52
  export const runPikkuFunc = async <In = any, Out = any>(
@@ -45,10 +54,9 @@ export const runPikkuFunc = async <In = any, Out = any>(
45
54
  wireId: string,
46
55
  funcName: string,
47
56
  {
48
- getAllServices,
49
57
  singletonServices,
58
+ createWireServices,
50
59
  data,
51
- userSession,
52
60
  auth: wiringAuth,
53
61
  inheritedMiddleware,
54
62
  wireMiddleware,
@@ -56,13 +64,10 @@ export const runPikkuFunc = async <In = any, Out = any>(
56
64
  wirePermissions,
57
65
  coerceDataFromSchema,
58
66
  tags = [],
59
- interaction,
67
+ wire,
60
68
  }: {
61
69
  singletonServices: CoreSingletonServices
62
- getAllServices: (
63
- session?: CoreUserSession
64
- ) => Promise<CoreServices> | CoreServices
65
- userSession?: UserSessionService<CoreUserSession>
70
+ createWireServices?: CreateWireServices
66
71
  data: () => Promise<In> | In
67
72
  auth?: boolean
68
73
  inheritedMiddleware?: MiddlewareMetadata[]
@@ -71,7 +76,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
71
76
  wirePermissions?: CorePermissionGroup | CorePikkuPermission[]
72
77
  coerceDataFromSchema?: boolean
73
78
  tags?: string[]
74
- interaction: PikkuInteraction
79
+ wire: PikkuWire
75
80
  }
76
81
  ): Promise<Out> => {
77
82
  const funcConfig = pikkuState('function', 'functions').get(funcName)
@@ -91,16 +96,23 @@ export const runPikkuFunc = async <In = any, Out = any>(
91
96
 
92
97
  // Helper function to run permissions and execute the function
93
98
  const executeFunction = async () => {
94
- const session = await userSession?.get()
99
+ const initialSession = wire.session?.freezeInitial()
100
+
101
+ const wireWithInitialSession: PikkuWire = {
102
+ ...wire,
103
+ initialSession,
104
+ }
105
+
95
106
  if (wiringAuth === true || funcConfig.auth === true) {
96
107
  // This means it was explicitly enabled in either wiring or function and has to be respected
97
- if (!session) {
108
+ if (!initialSession) {
98
109
  throw new ForbiddenError('Authentication required')
99
110
  }
100
111
  }
101
112
  if (wiringAuth === undefined && funcConfig.auth === undefined) {
102
113
  // We always default to requiring auth unless explicitly disabled
103
- if (!session) {
114
+ if (!initialSession) {
115
+ // TODO: Critical, we need to figure out how to make this work with different wirings
104
116
  // throw new ForbiddenError('Authentication required')
105
117
  }
106
118
  }
@@ -124,23 +136,37 @@ export const runPikkuFunc = async <In = any, Out = any>(
124
136
  }
125
137
  }
126
138
 
127
- const allServices = await getAllServices(session)
128
-
129
- // Run permissions check with combined permissions: inheritedPermissions (including tags) → wirePermissions → funcPermissions
130
139
  await runPermissions(wireType, wireId, {
131
140
  wireInheritedPermissions: mergedInheritedPermissions,
132
141
  wirePermissions: wirePermissions,
133
142
  funcInheritedPermissions: funcMeta.permissions,
134
143
  funcPermissions: funcConfig.permissions,
135
- allServices,
144
+ services: singletonServices,
145
+ wire: { ...wireWithInitialSession, rpc: undefined } as any,
136
146
  data: actualData,
137
- session,
138
147
  })
139
148
 
140
- return await funcConfig.func(allServices, actualData, session!)
149
+ const wireServices = await createWireServices?.(
150
+ singletonServices,
151
+ wireWithInitialSession
152
+ )
153
+ try {
154
+ const services = { ...singletonServices, ...wireServices }
155
+ const rpc = rpcService.getContextRPCService(
156
+ services,
157
+ wireWithInitialSession
158
+ )
159
+ return await funcConfig.func(services, actualData, {
160
+ ...wireWithInitialSession,
161
+ rpc,
162
+ })
163
+ } finally {
164
+ if (wireServices) {
165
+ await closeWireServices(singletonServices.logger, wireServices)
166
+ }
167
+ }
141
168
  }
142
169
 
143
- // Combine all middleware: inheritedMiddleware → wireMiddleware → funcMiddleware
144
170
  const allMiddleware = combineMiddleware(wireType, wireId, {
145
171
  wireInheritedMiddleware: inheritedMiddleware,
146
172
  wireMiddleware,
@@ -150,11 +176,8 @@ export const runPikkuFunc = async <In = any, Out = any>(
150
176
 
151
177
  if (allMiddleware.length > 0) {
152
178
  return (await runMiddleware<CorePikkuMiddleware>(
153
- {
154
- ...singletonServices,
155
- userSession,
156
- },
157
- interaction,
179
+ singletonServices,
180
+ wire,
158
181
  allMiddleware,
159
182
  executeFunction
160
183
  )) as Out
@@ -0,0 +1,188 @@
1
+ import { runMiddleware, combineMiddleware } from '../middleware-runner.js'
2
+ import { runPermissions } from '../permissions.js'
3
+ import { pikkuState } from '../pikku-state.js'
4
+ import { coerceTopLevelDataFromSchema, validateSchema } from '../schema.js'
5
+ import {
6
+ CoreServices,
7
+ CoreUserSession,
8
+ CorePikkuMiddleware,
9
+ PikkuWiringTypes,
10
+ PikkuWire,
11
+ MiddlewareMetadata,
12
+ PermissionMetadata,
13
+ CoreSingletonServices,
14
+ CreateWireServices,
15
+ } from '../types/core.types.js'
16
+ import {
17
+ CorePermissionGroup,
18
+ CorePikkuFunctionConfig,
19
+ CorePikkuPermission,
20
+ } from './functions.types.js'
21
+ import { SessionService } from '../services/user-session-service.js'
22
+ import { ForbiddenError } from '../errors/errors.js'
23
+ import { rpcService } from '../wirings/rpc/rpc-runner.js'
24
+ import { closeWireServices } from '../utils.js'
25
+
26
+ export const addFunction = (
27
+ funcName: string,
28
+ funcConfig: CorePikkuFunctionConfig<any, any>
29
+ ) => {
30
+ pikkuState('function', 'functions').set(funcName, funcConfig)
31
+ }
32
+
33
+ export const runPikkuFuncDirectly = async <In, Out>(
34
+ funcName: string,
35
+ allServices: CoreServices,
36
+ wire: PikkuWire,
37
+ data: In,
38
+ userSession?: SessionService<CoreUserSession>
39
+ ) => {
40
+ const funcConfig = pikkuState('function', 'functions').get(funcName)
41
+ if (!funcConfig) {
42
+ throw new Error(`Function not found: ${funcName}`)
43
+ }
44
+ // Inject session into wire
45
+ const wireWithSession = {
46
+ ...wire,
47
+ session: userSession,
48
+ }
49
+ return (await funcConfig.func(allServices, data, wireWithSession)) as Out
50
+ }
51
+
52
+ export const runPikkuFunc = async <In = any, Out = any>(
53
+ wireType: PikkuWiringTypes,
54
+ wireId: string,
55
+ funcName: string,
56
+ {
57
+ singletonServices,
58
+ createWireServices,
59
+ data,
60
+ auth: wiringAuth,
61
+ inheritedMiddleware,
62
+ wireMiddleware,
63
+ inheritedPermissions,
64
+ wirePermissions,
65
+ coerceDataFromSchema,
66
+ tags = [],
67
+ wire,
68
+ }: {
69
+ singletonServices: CoreSingletonServices
70
+ createWireServices?: CreateWireServices
71
+ data: () => Promise<In> | In
72
+ auth?: boolean
73
+ inheritedMiddleware?: MiddlewareMetadata[]
74
+ wireMiddleware?: CorePikkuMiddleware[]
75
+ inheritedPermissions?: PermissionMetadata[]
76
+ wirePermissions?: CorePermissionGroup | CorePikkuPermission[]
77
+ coerceDataFromSchema?: boolean
78
+ tags?: string[]
79
+ wire: PikkuWire
80
+ }
81
+ ): Promise<Out> => {
82
+ const funcConfig = pikkuState('function', 'functions').get(funcName)
83
+ if (!funcConfig) {
84
+ throw new Error(`Function not found: ${funcName}`)
85
+ }
86
+ const funcMeta = pikkuState('function', 'meta')[funcName]
87
+ if (!funcMeta) {
88
+ throw new Error(`Function meta not found: ${funcName}`)
89
+ }
90
+
91
+ // Convert tags to PermissionMetadata and merge with inheritedPermissions
92
+ const mergedInheritedPermissions: PermissionMetadata[] = [
93
+ ...(inheritedPermissions || []),
94
+ ...(tags?.map((tag) => ({ type: 'tag' as const, tag })) || []),
95
+ ]
96
+
97
+ // Populate initialSession from session.initial
98
+ const wireWithInitialSession = {
99
+ ...wire,
100
+ initialSession: wire.session?.initial,
101
+ }
102
+
103
+ // Helper function to run permissions and execute the function
104
+ const executeFunction = async () => {
105
+ const session = wireWithInitialSession.initialSession
106
+ if (wiringAuth === true || funcConfig.auth === true) {
107
+ // This means it was explicitly enabled in either wiring or function and has to be respected
108
+ if (!session) {
109
+ throw new ForbiddenError('Authentication required')
110
+ }
111
+ }
112
+ if (wiringAuth === undefined && funcConfig.auth === undefined) {
113
+ // We always default to requiring auth unless explicitly disabled
114
+ if (!session) {
115
+ // throw new ForbiddenError('Authentication required')
116
+ }
117
+ }
118
+
119
+ // Evaluate the data from the lazy function
120
+ const actualData = await data()
121
+
122
+ // Validate and coerce data if schema is defined
123
+ const inputSchemaName = funcMeta.inputSchemaName
124
+ if (inputSchemaName) {
125
+ // Validate request data against the defined schema, if any
126
+ await validateSchema(
127
+ singletonServices.logger,
128
+ singletonServices.schema,
129
+ inputSchemaName,
130
+ actualData
131
+ )
132
+ // Coerce (top level) query string parameters or date objects if specified by the schema
133
+ if (coerceDataFromSchema) {
134
+ coerceTopLevelDataFromSchema(inputSchemaName, actualData)
135
+ }
136
+ }
137
+
138
+ const rpcLessWire = { ...wireWithInitialSession, rpc: undefined }
139
+
140
+ await runPermissions(wireType, wireId, {
141
+ wireInheritedPermissions: mergedInheritedPermissions,
142
+ wirePermissions: wirePermissions,
143
+ funcInheritedPermissions: funcMeta.permissions,
144
+ funcPermissions: funcConfig.permissions,
145
+ services: singletonServices,
146
+ wire: rpcLessWire as any,
147
+ data: actualData,
148
+ })
149
+
150
+ const wireServices = await createWireServices?.(
151
+ singletonServices,
152
+ wireWithInitialSession
153
+ )
154
+ try {
155
+ const services = { ...singletonServices, ...wireServices }
156
+ const rpc = rpcService.getContextRPCService(
157
+ services,
158
+ wireWithInitialSession
159
+ )
160
+ return await funcConfig.func(services, actualData, {
161
+ ...wireWithInitialSession,
162
+ rpc,
163
+ })
164
+ } finally {
165
+ if (wireServices) {
166
+ await closeWireServices(singletonServices.logger, wireServices)
167
+ }
168
+ }
169
+ }
170
+
171
+ const allMiddleware = combineMiddleware(wireType, wireId, {
172
+ wireInheritedMiddleware: inheritedMiddleware,
173
+ wireMiddleware,
174
+ funcInheritedMiddleware: funcMeta.middleware,
175
+ funcMiddleware: funcConfig.middleware,
176
+ })
177
+
178
+ if (allMiddleware.length > 0) {
179
+ return (await runMiddleware<CorePikkuMiddleware>(
180
+ singletonServices,
181
+ wire,
182
+ allMiddleware,
183
+ executeFunction
184
+ )) as Out
185
+ }
186
+
187
+ return (await executeFunction()) as Out
188
+ }