@pikku/core 0.11.0 → 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.
- package/CHANGELOG.md +11 -1
- package/dist/errors/errors.d.ts +1 -1
- package/dist/errors/errors.js +3 -3
- package/dist/function/function-runner.d.ts +6 -7
- package/dist/function/function-runner.js +35 -16
- package/dist/function/functions.types.d.ts +22 -30
- package/dist/function/functions.types.js +9 -6
- package/dist/handle-error.d.ts +1 -1
- package/dist/handle-error.js +1 -1
- package/dist/middleware/auth-apikey.js +3 -3
- package/dist/middleware/auth-bearer.js +3 -3
- package/dist/middleware/auth-cookie.js +5 -5
- package/dist/middleware/timeout.js +3 -2
- package/dist/middleware-runner.d.ts +3 -6
- package/dist/middleware-runner.js +11 -12
- package/dist/permissions.d.ts +6 -6
- package/dist/permissions.js +15 -16
- package/dist/services/user-session-service.d.ts +7 -3
- package/dist/services/user-session-service.js +8 -1
- package/dist/types/core.types.d.ts +29 -38
- package/dist/types/core.types.js +3 -14
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +3 -3
- package/dist/wirings/channel/channel-common.js +2 -3
- package/dist/wirings/channel/channel-handler.d.ts +3 -2
- package/dist/wirings/channel/channel-handler.js +6 -9
- package/dist/wirings/channel/channel-runner.d.ts +2 -2
- package/dist/wirings/channel/channel.types.d.ts +10 -5
- package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
- package/dist/wirings/channel/local/local-channel-runner.js +19 -26
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +41 -46
- package/dist/wirings/cli/cli-runner.d.ts +5 -5
- package/dist/wirings/cli/cli-runner.js +10 -28
- package/dist/wirings/cli/cli.types.d.ts +15 -11
- package/dist/wirings/http/http-runner.d.ts +6 -6
- package/dist/wirings/http/http-runner.js +25 -39
- package/dist/wirings/http/http.types.d.ts +5 -10
- package/dist/wirings/mcp/mcp-runner.d.ts +2 -2
- package/dist/wirings/mcp/mcp-runner.js +12 -19
- package/dist/wirings/mcp/mcp.types.d.ts +6 -0
- package/dist/wirings/queue/queue-runner.d.ts +3 -3
- package/dist/wirings/queue/queue-runner.js +7 -17
- package/dist/wirings/queue/queue.types.d.ts +4 -11
- package/dist/wirings/rpc/rpc-runner.d.ts +10 -8
- package/dist/wirings/rpc/rpc-runner.js +36 -47
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -3
- package/dist/wirings/scheduler/scheduler-runner.js +13 -24
- package/dist/wirings/scheduler/scheduler.types.d.ts +3 -8
- package/dist/wirings/workflow/index.d.ts +11 -2
- package/dist/wirings/workflow/index.js +10 -2
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +12 -4
- package/dist/wirings/workflow/pikku-workflow-service.js +61 -79
- package/dist/wirings/workflow/workflow-runner.d.ts +3 -4
- package/dist/wirings/workflow/workflow-runner.js +11 -14
- package/dist/wirings/workflow/workflow.types.d.ts +114 -29
- package/package.json +2 -2
- package/src/errors/errors.ts +3 -3
- package/src/factory-functions.test.ts +9 -36
- package/src/function/function-runner.test.ts +57 -68
- package/src/function/function-runner.ts +51 -28
- package/src/function/function-runner.ts.bak +188 -0
- package/src/function/functions.types.ts +68 -51
- package/src/handle-error.ts +1 -1
- package/src/middleware/auth-apikey.test.ts +360 -0
- package/src/middleware/auth-apikey.ts +3 -7
- package/src/middleware/auth-bearer.test.ts +447 -0
- package/src/middleware/auth-bearer.ts +27 -33
- package/src/middleware/auth-cookie.test.ts +525 -0
- package/src/middleware/auth-cookie.ts +6 -6
- package/src/middleware/timeout.ts +4 -2
- package/src/middleware-runner.test.ts +58 -127
- package/src/middleware-runner.ts +13 -16
- package/src/permissions.test.ts +41 -45
- package/src/permissions.ts +21 -21
- package/src/services/user-session-service.ts +14 -4
- package/src/types/core.types.ts +67 -55
- package/src/utils.ts +4 -4
- package/src/wirings/channel/channel-common.ts +4 -7
- package/src/wirings/channel/channel-handler.ts +16 -22
- package/src/wirings/channel/channel-runner.ts +2 -2
- package/src/wirings/channel/channel.types.ts +14 -11
- package/src/wirings/channel/local/local-channel-runner.test.ts +5 -3
- package/src/wirings/channel/local/local-channel-runner.ts +23 -38
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +51 -77
- package/src/wirings/cli/cli-runner.test.ts +7 -7
- package/src/wirings/cli/cli-runner.ts +24 -62
- package/src/wirings/cli/cli.types.ts +22 -16
- package/src/wirings/http/http-runner.test.ts +8 -8
- package/src/wirings/http/http-runner.ts +29 -56
- package/src/wirings/http/http.types.ts +5 -14
- package/src/wirings/mcp/mcp-runner.ts +23 -48
- package/src/wirings/mcp/mcp.types.ts +6 -0
- package/src/wirings/queue/queue-runner.test.ts +641 -0
- package/src/wirings/queue/queue-runner.ts +10 -32
- package/src/wirings/queue/queue.types.ts +4 -11
- package/src/wirings/rpc/rpc-runner.ts +41 -55
- package/src/wirings/scheduler/scheduler-runner.test.ts +627 -0
- package/src/wirings/scheduler/scheduler-runner.ts +24 -50
- package/src/wirings/scheduler/scheduler.types.ts +3 -9
- package/src/wirings/workflow/index.ts +24 -3
- package/src/wirings/workflow/pikku-workflow-service.ts +83 -93
- package/src/wirings/workflow/workflow-runner.ts +12 -25
- package/src/wirings/workflow/workflow.types.ts +144 -54
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
224
|
+
runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
|
|
229
225
|
singletonServices: mockSingletonServices,
|
|
230
226
|
getAllServices: () => mockServices,
|
|
231
227
|
data: () => ({}),
|
|
232
228
|
auth: false,
|
|
233
|
-
|
|
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(
|
|
248
|
+
runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
|
|
253
249
|
singletonServices: mockSingletonServices,
|
|
254
250
|
getAllServices: () => mockServices,
|
|
255
251
|
data: () => ({}),
|
|
256
252
|
auth: false,
|
|
257
|
-
|
|
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
|
-
|
|
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
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
485
|
+
func: async (services, data, wire) => {
|
|
496
486
|
receivedServices = services
|
|
497
487
|
receivedData = data
|
|
498
|
-
|
|
488
|
+
receivedWire = wire
|
|
499
489
|
return 'success'
|
|
500
490
|
},
|
|
501
491
|
})
|
|
502
492
|
|
|
503
|
-
await runPikkuFunc(
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
{
|
|
508
|
-
|
|
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.
|
|
500
|
+
assert.deepEqual(receivedServices, mockServices)
|
|
518
501
|
assert.equal(receivedData, testData)
|
|
519
|
-
|
|
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
|
|
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
|
|
518
|
+
const asyncCreateWireServices = async () => {
|
|
533
519
|
// Simulate async service creation
|
|
534
520
|
await new Promise((resolve) => setTimeout(resolve, 1))
|
|
535
|
-
return
|
|
521
|
+
return wireServices
|
|
536
522
|
}
|
|
537
523
|
|
|
538
524
|
const result = await runPikkuFunc(
|
|
539
|
-
|
|
525
|
+
'rpc',
|
|
540
526
|
Math.random().toString(),
|
|
541
527
|
'testFunc',
|
|
542
528
|
{
|
|
543
529
|
singletonServices: mockSingletonServices,
|
|
544
|
-
|
|
530
|
+
createWireServices: asyncCreateWireServices,
|
|
545
531
|
data: () => ({}),
|
|
546
532
|
auth: false,
|
|
547
|
-
|
|
533
|
+
wire: {},
|
|
548
534
|
}
|
|
549
535
|
)
|
|
550
536
|
|
|
551
537
|
assert.equal(result, 'success')
|
|
552
|
-
assert.
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
67
|
+
wire,
|
|
60
68
|
}: {
|
|
61
69
|
singletonServices: CoreSingletonServices
|
|
62
|
-
|
|
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
|
-
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
-
|
|
144
|
+
services: singletonServices,
|
|
145
|
+
wire: { ...wireWithInitialSession, rpc: undefined } as any,
|
|
136
146
|
data: actualData,
|
|
137
|
-
session,
|
|
138
147
|
})
|
|
139
148
|
|
|
140
|
-
|
|
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
|
-
|
|
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
|
+
}
|