@pikku/core 0.9.5 → 0.9.7

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 (73) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/function/function-runner.d.ts +2 -2
  3. package/dist/function/function-runner.js +3 -3
  4. package/dist/function/functions.types.d.ts +4 -0
  5. package/dist/function/functions.types.js +6 -1
  6. package/dist/index.d.ts +3 -3
  7. package/dist/index.js +3 -3
  8. package/dist/middleware-runner.d.ts +5 -4
  9. package/dist/middleware-runner.js +20 -6
  10. package/dist/permissions.d.ts +3 -3
  11. package/dist/permissions.js +30 -8
  12. package/dist/pikku-state.d.ts +2 -4
  13. package/dist/pikku-state.js +3 -2
  14. package/dist/schema.js +8 -6
  15. package/dist/services/local-content.js +1 -0
  16. package/dist/types/core.types.d.ts +4 -0
  17. package/dist/types/core.types.js +6 -0
  18. package/dist/utils.d.ts +1 -0
  19. package/dist/utils.js +17 -0
  20. package/dist/wirings/channel/channel-handler.js +2 -1
  21. package/dist/wirings/channel/channel-runner.d.ts +2 -0
  22. package/dist/wirings/channel/channel-runner.js +23 -25
  23. package/dist/wirings/channel/local/local-channel-runner.js +5 -3
  24. package/dist/wirings/channel/serverless/serverless-channel-runner.js +4 -2
  25. package/dist/wirings/http/http-runner.js +36 -53
  26. package/dist/wirings/http/http.types.d.ts +1 -1
  27. package/dist/wirings/http/pikku-fetch-http-request.js +4 -1
  28. package/dist/wirings/http/routers/http-router.d.ts +12 -0
  29. package/dist/wirings/http/routers/http-router.js +2 -0
  30. package/dist/wirings/http/routers/path-to-regex.d.ts +10 -0
  31. package/dist/wirings/http/routers/path-to-regex.js +118 -0
  32. package/dist/wirings/mcp/mcp-runner.d.ts +1 -1
  33. package/dist/wirings/mcp/mcp-runner.js +3 -2
  34. package/dist/wirings/queue/queue-runner.js +3 -2
  35. package/dist/wirings/rpc/rpc-runner.js +2 -1
  36. package/dist/wirings/scheduler/scheduler-runner.d.ts +1 -1
  37. package/dist/wirings/scheduler/scheduler-runner.js +3 -2
  38. package/package.json +1 -1
  39. package/run-tests.sh +1 -1
  40. package/src/factory-functions.test.ts +37 -0
  41. package/src/function/function-runner.test.ts +101 -52
  42. package/src/function/function-runner.ts +5 -2
  43. package/src/function/functions.types.ts +13 -0
  44. package/src/index.ts +3 -11
  45. package/src/middleware-runner.test.ts +71 -43
  46. package/src/middleware-runner.ts +43 -17
  47. package/src/permissions.test.ts +21 -17
  48. package/src/permissions.ts +68 -26
  49. package/src/pikku-state.ts +5 -3
  50. package/src/schema.ts +8 -6
  51. package/src/services/local-content.ts +1 -0
  52. package/src/types/core.types.ts +12 -0
  53. package/src/utils.ts +19 -0
  54. package/src/wirings/channel/channel-handler.ts +17 -11
  55. package/src/wirings/channel/channel-runner.ts +31 -25
  56. package/src/wirings/channel/local/local-channel-runner.test.ts +4 -0
  57. package/src/wirings/channel/local/local-channel-runner.ts +5 -4
  58. package/src/wirings/channel/serverless/serverless-channel-runner.ts +13 -11
  59. package/src/wirings/http/http-runner.test.ts +18 -6
  60. package/src/wirings/http/http-runner.ts +55 -74
  61. package/src/wirings/http/http.types.ts +1 -1
  62. package/src/wirings/http/pikku-fetch-http-request.ts +4 -1
  63. package/src/wirings/http/routers/http-router.ts +15 -0
  64. package/src/wirings/http/routers/path-to-regex.test.ts +309 -0
  65. package/src/wirings/http/routers/path-to-regex.ts +162 -0
  66. package/src/wirings/mcp/mcp-runner.ts +18 -12
  67. package/src/wirings/queue/queue-runner.ts +15 -7
  68. package/src/wirings/rpc/rpc-runner.ts +21 -16
  69. package/src/wirings/scheduler/scheduler-runner.ts +18 -12
  70. package/tsconfig.tsbuildinfo +1 -1
  71. package/dist/pikku-function.d.ts +0 -1
  72. package/dist/pikku-function.js +0 -1
  73. package/src/pikku-function.ts +0 -1
@@ -3,7 +3,11 @@ 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 { CoreServices, CorePikkuMiddleware } from '../types/core.types.js'
6
+ import {
7
+ CoreServices,
8
+ CorePikkuMiddleware,
9
+ PikkuWiringTypes,
10
+ } from '../types/core.types.js'
7
11
  import { CorePermissionGroup } from './functions.types.js'
8
12
 
9
13
  beforeEach(() => {
@@ -52,12 +56,17 @@ describe('runPikkuFunc - Integration Tests', () => {
52
56
  tags: ['funcTag'],
53
57
  })
54
58
 
55
- const result = await runPikkuFunc('testFunc', {
56
- getAllServices: () => mockServices,
57
- data: {},
58
- middleware: [createMiddleware('wiringMiddleware')],
59
- tags: ['wiringTag'],
60
- })
59
+ const result = await runPikkuFunc(
60
+ PikkuWiringTypes.rpc,
61
+ Math.random().toString(),
62
+ 'testFunc',
63
+ {
64
+ getAllServices: () => mockServices,
65
+ data: {},
66
+ middleware: [createMiddleware('wiringMiddleware')],
67
+ tags: ['wiringTag'],
68
+ }
69
+ )
61
70
 
62
71
  assert.equal(result, 'success')
63
72
  // Order: wiringTags, wiringMiddleware, funcMiddleware, funcTags
@@ -114,12 +123,17 @@ describe('runPikkuFunc - Integration Tests', () => {
114
123
  tags: ['funcTag'],
115
124
  })
116
125
 
117
- const result = await runPikkuFunc('testFunc', {
118
- getAllServices: () => mockServices,
119
- data: {},
120
- permissions: wiringPermissions,
121
- tags: ['wiringTag'],
122
- })
126
+ const result = await runPikkuFunc(
127
+ PikkuWiringTypes.rpc,
128
+ Math.random().toString(),
129
+ 'testFunc',
130
+ {
131
+ getAllServices: () => mockServices,
132
+ data: {},
133
+ permissions: wiringPermissions,
134
+ tags: ['wiringTag'],
135
+ }
136
+ )
123
137
 
124
138
  assert.equal(result, 'success')
125
139
  // Order: wiringTags → wiringPermissions → funcTags → funcPermissions
@@ -142,13 +156,13 @@ describe('runPikkuFunc - Integration Tests', () => {
142
156
  })
143
157
 
144
158
  await assert.rejects(
145
- runPikkuFunc('testFunc', {
159
+ runPikkuFunc(PikkuWiringTypes.rpc, Math.random().toString(), 'testFunc', {
146
160
  getAllServices: () => mockServices,
147
161
  data: {},
148
162
  tags: ['wiringTag'],
149
163
  }),
150
164
  {
151
- message: 'Permission denied - wiring tag permissions',
165
+ message: 'Permission denied',
152
166
  }
153
167
  )
154
168
  })
@@ -163,13 +177,13 @@ describe('runPikkuFunc - Integration Tests', () => {
163
177
  })
164
178
 
165
179
  await assert.rejects(
166
- runPikkuFunc('testFunc', {
180
+ runPikkuFunc(PikkuWiringTypes.rpc, Math.random().toString(), 'testFunc', {
167
181
  getAllServices: () => mockServices,
168
182
  data: {},
169
183
  permissions: wiringPermissions,
170
184
  }),
171
185
  {
172
- message: 'Permission denied - wiring permissions',
186
+ message: 'Permission denied',
173
187
  }
174
188
  )
175
189
  })
@@ -185,12 +199,12 @@ describe('runPikkuFunc - Integration Tests', () => {
185
199
  })
186
200
 
187
201
  await assert.rejects(
188
- runPikkuFunc('testFunc', {
202
+ runPikkuFunc(PikkuWiringTypes.rpc, Math.random().toString(), 'testFunc', {
189
203
  getAllServices: () => mockServices,
190
204
  data: {},
191
205
  }),
192
206
  {
193
- message: 'Permission denied - function tag permissions',
207
+ message: 'Permission denied',
194
208
  }
195
209
  )
196
210
  })
@@ -206,12 +220,12 @@ describe('runPikkuFunc - Integration Tests', () => {
206
220
  })
207
221
 
208
222
  await assert.rejects(
209
- runPikkuFunc('testFunc', {
223
+ runPikkuFunc(PikkuWiringTypes.rpc, Math.random().toString(), 'testFunc', {
210
224
  getAllServices: () => mockServices,
211
225
  data: {},
212
226
  }),
213
227
  {
214
- message: 'Permission denied - function permissions',
228
+ message: 'Permission denied',
215
229
  }
216
230
  )
217
231
  })
@@ -237,10 +251,15 @@ describe('runPikkuFunc - Integration Tests', () => {
237
251
  tags: ['testTag'], // Same middleware via tag
238
252
  })
239
253
 
240
- await runPikkuFunc('testFunc', {
241
- getAllServices: () => mockServices,
242
- data: {},
243
- })
254
+ await runPikkuFunc(
255
+ PikkuWiringTypes.rpc,
256
+ Math.random().toString(),
257
+ 'testFunc',
258
+ {
259
+ getAllServices: () => mockServices,
260
+ data: {},
261
+ }
262
+ )
244
263
 
245
264
  // Should only execute once due to deduplication
246
265
  assert.equal(executionCount, 1)
@@ -281,10 +300,15 @@ describe('runPikkuFunc - Integration Tests', () => {
281
300
  tags: ['mixedTag'],
282
301
  })
283
302
 
284
- const result = await runPikkuFunc('testFunc', {
285
- getAllServices: () => mockServices,
286
- data: {},
287
- })
303
+ const result = await runPikkuFunc(
304
+ PikkuWiringTypes.rpc,
305
+ Math.random().toString(),
306
+ 'testFunc',
307
+ {
308
+ getAllServices: () => mockServices,
309
+ data: {},
310
+ }
311
+ )
288
312
 
289
313
  assert.equal(result, 'success')
290
314
  // Should execute tag permissions first, then function permissions
@@ -301,10 +325,15 @@ describe('runPikkuFunc - Integration Tests', () => {
301
325
  func: async () => 'simple success',
302
326
  })
303
327
 
304
- const result = await runPikkuFunc('simpleFunc', {
305
- getAllServices: () => mockServices,
306
- data: {},
307
- })
328
+ const result = await runPikkuFunc(
329
+ PikkuWiringTypes.rpc,
330
+ Math.random().toString(),
331
+ 'simpleFunc',
332
+ {
333
+ getAllServices: () => mockServices,
334
+ data: {},
335
+ }
336
+ )
308
337
 
309
338
  assert.equal(result, 'simple success')
310
339
  })
@@ -337,12 +366,17 @@ describe('runPikkuFunc - Integration Tests', () => {
337
366
  },
338
367
  })
339
368
 
340
- const result = await runPikkuFunc('testFunc', {
341
- getAllServices: () => mockServices,
342
- data: {},
343
- middleware: [wiringMiddleware],
344
- permissions: wiringPermissions,
345
- })
369
+ const result = await runPikkuFunc(
370
+ PikkuWiringTypes.rpc,
371
+ Math.random().toString(),
372
+ 'testFunc',
373
+ {
374
+ getAllServices: () => mockServices,
375
+ data: {},
376
+ middleware: [wiringMiddleware],
377
+ permissions: wiringPermissions,
378
+ }
379
+ )
346
380
 
347
381
  assert.equal(result, 'success')
348
382
  assert.deepEqual(executionOrder, [
@@ -382,10 +416,15 @@ describe('runPikkuFunc - Integration Tests', () => {
382
416
  permissions: funcPermissions,
383
417
  })
384
418
 
385
- const result = await runPikkuFunc('testFunc', {
386
- getAllServices: () => mockServices,
387
- data: {},
388
- })
419
+ const result = await runPikkuFunc(
420
+ PikkuWiringTypes.rpc,
421
+ Math.random().toString(),
422
+ 'testFunc',
423
+ {
424
+ getAllServices: () => mockServices,
425
+ data: {},
426
+ }
427
+ )
389
428
 
390
429
  assert.equal(result, 'success')
391
430
  assert.deepEqual(executionOrder, [
@@ -412,11 +451,16 @@ describe('runPikkuFunc - Integration Tests', () => {
412
451
  },
413
452
  })
414
453
 
415
- await runPikkuFunc('testFunc', {
416
- getAllServices: () => mockServices,
417
- data: testData,
418
- session: testSession,
419
- })
454
+ await runPikkuFunc(
455
+ PikkuWiringTypes.rpc,
456
+ Math.random().toString(),
457
+ 'testFunc',
458
+ {
459
+ getAllServices: () => mockServices,
460
+ data: testData,
461
+ session: testSession,
462
+ }
463
+ )
420
464
 
421
465
  assert.equal(receivedServices, mockServices)
422
466
  assert.equal(receivedData, testData)
@@ -439,10 +483,15 @@ describe('runPikkuFunc - Integration Tests', () => {
439
483
  return mockServices
440
484
  }
441
485
 
442
- const result = await runPikkuFunc('testFunc', {
443
- getAllServices: asyncGetServices,
444
- data: {},
445
- })
486
+ const result = await runPikkuFunc(
487
+ PikkuWiringTypes.rpc,
488
+ Math.random().toString(),
489
+ 'testFunc',
490
+ {
491
+ getAllServices: asyncGetServices,
492
+ data: {},
493
+ }
494
+ )
446
495
 
447
496
  assert.equal(result, 'success')
448
497
  assert.equal(servicesProvided, mockServices)
@@ -7,6 +7,7 @@ import {
7
7
  CoreServices,
8
8
  CoreUserSession,
9
9
  CorePikkuMiddleware,
10
+ PikkuWiringTypes,
10
11
  } from '../types/core.types.js'
11
12
  import {
12
13
  CorePermissionGroup,
@@ -42,6 +43,8 @@ export const runPikkuFuncDirectly = async <In, Out>(
42
43
  }
43
44
 
44
45
  export const runPikkuFunc = async <In = any, Out = any>(
46
+ wireType: PikkuWiringTypes,
47
+ wireId: string,
45
48
  funcName: string,
46
49
  {
47
50
  getAllServices,
@@ -94,7 +97,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
94
97
  }
95
98
 
96
99
  // Run permission checks in the specified order
97
- await runPermissions({
100
+ await runPermissions(wireType, wireId, {
98
101
  wiringTags: tags,
99
102
  wiringPermissions,
100
103
  funcTags: funcConfig.tags,
@@ -105,7 +108,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
105
108
  })
106
109
 
107
110
  // Combine all middleware: wiring tags → wiring middleware → func middleware → func tags
108
- const allMiddleware = combineMiddleware({
111
+ const allMiddleware = combineMiddleware(wireType, wireId, {
109
112
  wiringTags: tags,
110
113
  wiringMiddleware,
111
114
  funcMiddleware: funcConfig.middleware,
@@ -74,6 +74,19 @@ export type CorePikkuPermission<
74
74
  Session extends CoreUserSession = CoreUserSession,
75
75
  > = (services: Services, data: In, session?: Session) => Promise<boolean>
76
76
 
77
+ /**
78
+ * Factory function for creating permissions with tree-shaking support
79
+ */
80
+ export const pikkuPermission = <
81
+ In = any,
82
+ Services extends CoreSingletonServices = CoreServices,
83
+ Session extends CoreUserSession = CoreUserSession,
84
+ >(
85
+ permission: CorePikkuPermission<In, Services, Session>
86
+ ): CorePikkuPermission<In, Services, Session> => {
87
+ return permission
88
+ }
89
+
77
90
  export type CorePermissionGroup<PikkuPermission = CorePikkuPermission<any>> =
78
91
  | Record<string, PikkuPermission | PikkuPermission[]>
79
92
  | undefined
package/src/index.ts CHANGED
@@ -18,19 +18,11 @@ export * from './wirings/queue/index.js'
18
18
  export * from './wirings/mcp/index.js'
19
19
  export * from './errors/index.js'
20
20
  export * from './middleware/index.js'
21
- export * from './time-utils.js'
22
21
  export * from './utils.js'
22
+ export * from './time-utils.js'
23
23
  export { pikkuState } from './pikku-state.js'
24
- export {
25
- runMiddleware,
26
- addMiddleware,
27
- combineMiddleware,
28
- } from './middleware-runner.js'
29
- export {
30
- addPermission,
31
- getPermissionsForTags,
32
- runPermissions,
33
- } from './permissions.js'
24
+ export { addMiddleware, runMiddleware } from './middleware-runner.js'
25
+ export { addPermission } from './permissions.js'
34
26
  export { wireHTTP, addHTTPMiddleware } from './wirings/http/http-runner.js'
35
27
  export { wireChannel } from './wirings/channel/channel-runner.js'
36
28
  export { wireScheduler } from './wirings/scheduler/scheduler-runner.js'
@@ -3,11 +3,10 @@ import assert from 'node:assert'
3
3
  import {
4
4
  combineMiddleware,
5
5
  addMiddleware,
6
- getMiddlewareForTags,
7
6
  runMiddleware,
8
7
  } from './middleware-runner.js'
9
8
  import { resetPikkuState } from './pikku-state.js'
10
- import { CorePikkuMiddleware } from './types/core.types.js'
9
+ import { CorePikkuMiddleware, PikkuWiringTypes } from './types/core.types.js'
11
10
 
12
11
  beforeEach(() => {
13
12
  resetPikkuState()
@@ -15,17 +14,24 @@ beforeEach(() => {
15
14
 
16
15
  describe('combineMiddleware', () => {
17
16
  test('should return empty array when no parameters provided', () => {
18
- const result = combineMiddleware()
17
+ const result = combineMiddleware(
18
+ PikkuWiringTypes.http,
19
+ Math.random().toString()
20
+ )
19
21
  assert.deepEqual(result, [])
20
22
  })
21
23
 
22
24
  test('should return empty array when all parameters are undefined', () => {
23
- const result = combineMiddleware({
24
- wiringMiddleware: undefined,
25
- wiringTags: undefined,
26
- funcMiddleware: undefined,
27
- funcTags: undefined,
28
- })
25
+ const result = combineMiddleware(
26
+ PikkuWiringTypes.http,
27
+ Math.random().toString(),
28
+ {
29
+ wiringMiddleware: undefined,
30
+ wiringTags: undefined,
31
+ funcMiddleware: undefined,
32
+ funcTags: undefined,
33
+ }
34
+ )
29
35
  assert.deepEqual(result, [])
30
36
  })
31
37
 
@@ -45,9 +51,13 @@ describe('combineMiddleware', () => {
45
51
  await next()
46
52
  }
47
53
 
48
- const result = combineMiddleware({
49
- wiringMiddleware: [mockMiddleware1, mockMiddleware2],
50
- })
54
+ const result = combineMiddleware(
55
+ PikkuWiringTypes.http,
56
+ Math.random().toString(),
57
+ {
58
+ wiringMiddleware: [mockMiddleware1, mockMiddleware2],
59
+ }
60
+ )
51
61
 
52
62
  assert.equal(result.length, 2)
53
63
  assert.equal(result[0], mockMiddleware1)
@@ -70,9 +80,13 @@ describe('combineMiddleware', () => {
70
80
  await next()
71
81
  }
72
82
 
73
- const result = combineMiddleware({
74
- funcMiddleware: [mockMiddleware1, mockMiddleware2],
75
- })
83
+ const result = combineMiddleware(
84
+ PikkuWiringTypes.http,
85
+ Math.random().toString(),
86
+ {
87
+ funcMiddleware: [mockMiddleware1, mockMiddleware2],
88
+ }
89
+ )
76
90
 
77
91
  assert.equal(result.length, 2)
78
92
  assert.equal(result[0], mockMiddleware1)
@@ -114,12 +128,16 @@ describe('combineMiddleware', () => {
114
128
  await next()
115
129
  }
116
130
 
117
- const result = combineMiddleware({
118
- wiringMiddleware: [wiringMiddleware],
119
- wiringTags: ['wiringTag'],
120
- funcMiddleware: [funcMiddleware],
121
- funcTags: ['funcTag'],
122
- })
131
+ const result = combineMiddleware(
132
+ PikkuWiringTypes.http,
133
+ Math.random().toString(),
134
+ {
135
+ wiringMiddleware: [wiringMiddleware],
136
+ wiringTags: ['wiringTag'],
137
+ funcMiddleware: [funcMiddleware],
138
+ funcTags: ['funcTag'],
139
+ }
140
+ )
123
141
 
124
142
  assert.equal(result.length, 4)
125
143
  // Order: wiringTags, wiringMiddleware, funcMiddleware, funcTags
@@ -140,9 +158,13 @@ describe('combineMiddleware', () => {
140
158
 
141
159
  addMiddleware('testTag', [taggedMiddleware])
142
160
 
143
- const result = combineMiddleware({
144
- wiringTags: ['testTag'],
145
- })
161
+ const result = combineMiddleware(
162
+ PikkuWiringTypes.http,
163
+ Math.random().toString(),
164
+ {
165
+ wiringTags: ['testTag'],
166
+ }
167
+ )
146
168
 
147
169
  assert.equal(result.length, 1)
148
170
  assert.equal(result[0], taggedMiddleware)
@@ -159,9 +181,13 @@ describe('combineMiddleware', () => {
159
181
 
160
182
  addMiddleware('funcTestTag', [taggedMiddleware])
161
183
 
162
- const result = combineMiddleware({
163
- funcTags: ['funcTestTag'],
164
- })
184
+ const result = combineMiddleware(
185
+ PikkuWiringTypes.http,
186
+ Math.random().toString(),
187
+ {
188
+ funcTags: ['funcTestTag'],
189
+ }
190
+ )
165
191
 
166
192
  assert.equal(result.length, 1)
167
193
  assert.equal(result[0], taggedMiddleware)
@@ -186,9 +212,13 @@ describe('combineMiddleware', () => {
186
212
  addMiddleware('tag1', [middleware1])
187
213
  addMiddleware('tag2', [middleware2])
188
214
 
189
- const result = combineMiddleware({
190
- wiringTags: ['tag1', 'tag2'],
191
- })
215
+ const result = combineMiddleware(
216
+ PikkuWiringTypes.http,
217
+ Math.random().toString(),
218
+ {
219
+ wiringTags: ['tag1', 'tag2'],
220
+ }
221
+ )
192
222
 
193
223
  assert.equal(result.length, 2)
194
224
  assert.equal(result[0], middleware1)
@@ -206,10 +236,14 @@ describe('combineMiddleware', () => {
206
236
 
207
237
  addMiddleware('existingTag', [middleware])
208
238
 
209
- const result = combineMiddleware({
210
- wiringTags: ['existingTag', 'nonExistentTag'],
211
- funcTags: ['anotherNonExistentTag'],
212
- })
239
+ const result = combineMiddleware(
240
+ PikkuWiringTypes.http,
241
+ Math.random().toString(),
242
+ {
243
+ wiringTags: ['existingTag', 'nonExistentTag'],
244
+ funcTags: ['anotherNonExistentTag'],
245
+ }
246
+ )
213
247
 
214
248
  assert.equal(result.length, 1)
215
249
  assert.equal(result[0], middleware)
@@ -238,18 +272,12 @@ describe('runMiddleware', () => {
238
272
  await next()
239
273
  }
240
274
 
241
- // Pass same middleware multiple times
242
- const duplicatedMiddleware = [
243
- middleware1,
244
- middleware2,
245
- middleware1,
246
- middleware2,
247
- ]
248
-
249
275
  await runMiddleware(
250
276
  {} as any,
251
277
  {} as any,
252
- duplicatedMiddleware,
278
+ combineMiddleware(PikkuWiringTypes.rpc, Math.random().toString(), {
279
+ wiringMiddleware: [middleware1, middleware2, middleware1, middleware2],
280
+ }),
253
281
  async () => {
254
282
  executionOrder.push('main')
255
283
  }
@@ -3,8 +3,10 @@ import {
3
3
  CoreSingletonServices,
4
4
  PikkuInteraction,
5
5
  CorePikkuMiddleware,
6
+ PikkuWiringTypes,
6
7
  } from './types/core.types.js'
7
8
  import { pikkuState } from './pikku-state.js'
9
+ import { freezeDedupe } from './utils.js'
8
10
 
9
11
  /**
10
12
  * Runs a chain of middleware functions in sequence before executing the main function.
@@ -28,15 +30,14 @@ export const runMiddleware = async <Middleware extends CorePikkuMiddleware>(
28
30
  userSession?: UserSessionService<any>
29
31
  },
30
32
  interaction: PikkuInteraction,
31
- middlewares: Middleware[],
33
+ middlewares: readonly Middleware[],
32
34
  main?: () => Promise<unknown>
33
35
  ): Promise<unknown> => {
34
36
  // Deduplicate middleware using Set to avoid running the same middleware multiple times
35
- const uniqueMiddleware = Array.from(new Set(middlewares))
36
37
  let result: any
37
38
  const dispatch = async (index: number): Promise<any> => {
38
- if (uniqueMiddleware && index < uniqueMiddleware.length) {
39
- return await uniqueMiddleware[index]!(services as any, interaction, () =>
39
+ if (middlewares && index < middlewares.length) {
40
+ return await middlewares[index]!(services as any, interaction, () =>
40
41
  dispatch(index + 1)
41
42
  )
42
43
  } else if (main) {
@@ -123,6 +124,18 @@ export const getMiddlewareForTags = (
123
124
  return applicableMiddleware
124
125
  }
125
126
 
127
+ const middlewareCache: Record<
128
+ PikkuWiringTypes,
129
+ Record<string, readonly CorePikkuMiddleware[]>
130
+ > = {
131
+ [PikkuWiringTypes.http]: {},
132
+ [PikkuWiringTypes.rpc]: {},
133
+ [PikkuWiringTypes.channel]: {},
134
+ [PikkuWiringTypes.queue]: {},
135
+ [PikkuWiringTypes.scheduler]: {},
136
+ [PikkuWiringTypes.mcp]: {},
137
+ }
138
+
126
139
  /**
127
140
  * Combines tag-based middleware with wiring-specific middleware and function-level middleware.
128
141
  *
@@ -146,17 +159,27 @@ export const getMiddlewareForTags = (
146
159
  * })
147
160
  * ```
148
161
  */
149
- export const combineMiddleware = ({
150
- wiringMiddleware,
151
- wiringTags,
152
- funcMiddleware,
153
- funcTags,
154
- }: {
155
- wiringMiddleware?: CorePikkuMiddleware[]
156
- wiringTags?: string[]
157
- funcMiddleware?: CorePikkuMiddleware[]
158
- funcTags?: string[]
159
- } = {}): CorePikkuMiddleware[] => {
162
+ export const combineMiddleware = (
163
+ wireType: PikkuWiringTypes,
164
+ uid: string,
165
+ {
166
+ httpMiddleware,
167
+ wiringMiddleware,
168
+ wiringTags,
169
+ funcMiddleware,
170
+ funcTags,
171
+ }: {
172
+ httpMiddleware?: CorePikkuMiddleware[]
173
+ wiringMiddleware?: CorePikkuMiddleware[]
174
+ wiringTags?: string[]
175
+ funcMiddleware?: CorePikkuMiddleware[]
176
+ funcTags?: string[]
177
+ } = {}
178
+ ): readonly CorePikkuMiddleware[] => {
179
+ if (middlewareCache[wireType][uid]) {
180
+ return middlewareCache[wireType][uid]
181
+ }
182
+
160
183
  // Run middleware in specific order:
161
184
  // 1) wiringTags middleware
162
185
  // 2) wiringMiddleware
@@ -165,10 +188,13 @@ export const combineMiddleware = ({
165
188
  const wiringTaggedMiddleware = getMiddlewareForTags(wiringTags)
166
189
  const funcTaggedMiddleware = getMiddlewareForTags(funcTags)
167
190
 
168
- return [
191
+ middlewareCache[wireType][uid] = freezeDedupe([
192
+ ...(httpMiddleware || []),
169
193
  ...wiringTaggedMiddleware,
170
194
  ...(wiringMiddleware || []),
171
195
  ...(funcMiddleware || []),
172
196
  ...funcTaggedMiddleware,
173
- ]
197
+ ]) as readonly CorePikkuMiddleware[]
198
+
199
+ return middlewareCache[wireType][uid]
174
200
  }