@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
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  CoreServices,
3
- CoreUserSession,
4
3
  PikkuWiringTypes,
5
4
  PermissionMetadata,
5
+ PikkuWire,
6
6
  } from './types/core.types.js'
7
7
  import {
8
8
  CorePermissionGroup,
@@ -16,14 +16,14 @@ import { freezeDedupe } from './utils.js'
16
16
  * This function validates permissions by iterating over permission groups and executing the corresponding permission functions. If all functions in at least one group return true, the permission is considered valid.
17
17
  * @param services - The core services required for permission validation.
18
18
  * @param data - The data to be used in the permission validation functions.
19
- * @param session - An optional user session for permission validation.
19
+ * @param wire - The wire object containing request/response context and session.
20
20
  * @returns A promise that resolves to void.
21
21
  */
22
- export const verifyPermissions = async (
22
+ export const verifyPermissions = async <Out = any>(
23
23
  permissions: CorePermissionGroup,
24
24
  services: CoreServices,
25
25
  data: any,
26
- session?: CoreUserSession
26
+ wire: PikkuWire<any, never, any, never, never, never>
27
27
  ): Promise<boolean> => {
28
28
  if (!permissions) {
29
29
  return true
@@ -38,13 +38,13 @@ export const verifyPermissions = async (
38
38
  for (const funcs of permissionGroups) {
39
39
  if (funcs instanceof Array) {
40
40
  const permissioned = await Promise.all(
41
- funcs.map((func) => func(services, data, session))
41
+ funcs.map((func) => func(services, data, wire))
42
42
  )
43
43
  if (permissioned.every((result) => result)) {
44
44
  valid = true
45
45
  }
46
46
  } else {
47
- valid = await funcs(services, data, session)
47
+ valid = await funcs(services, data, wire as any)
48
48
  }
49
49
  if (valid) {
50
50
  return true
@@ -190,13 +190,14 @@ const combinedPermissionsCache: Record<
190
190
  PikkuWiringTypes,
191
191
  Record<string, readonly (CorePermissionGroup | CorePikkuPermission)[]>
192
192
  > = {
193
- [PikkuWiringTypes.http]: {},
194
- [PikkuWiringTypes.rpc]: {},
195
- [PikkuWiringTypes.channel]: {},
196
- [PikkuWiringTypes.queue]: {},
197
- [PikkuWiringTypes.scheduler]: {},
198
- [PikkuWiringTypes.mcp]: {},
199
- [PikkuWiringTypes.cli]: {},
193
+ http: {},
194
+ rpc: {},
195
+ channel: {},
196
+ queue: {},
197
+ scheduler: {},
198
+ mcp: {},
199
+ cli: {},
200
+ workflow: {},
200
201
  }
201
202
 
202
203
  /**
@@ -334,17 +335,17 @@ export const runPermissions = async (
334
335
  wirePermissions,
335
336
  funcInheritedPermissions,
336
337
  funcPermissions,
337
- allServices,
338
+ services,
339
+ wire,
338
340
  data,
339
- session,
340
341
  }: {
341
342
  wireInheritedPermissions?: PermissionMetadata[]
342
343
  wirePermissions?: CorePermissionGroup | CorePikkuPermission[]
343
344
  funcInheritedPermissions?: PermissionMetadata[]
344
345
  funcPermissions?: CorePermissionGroup | CorePikkuPermission[]
345
- allServices: CoreServices
346
+ services: CoreServices
347
+ wire: PikkuWire<any, never, any, never, never, never>
346
348
  data: any
347
- session?: CoreUserSession
348
349
  }
349
350
  ) => {
350
351
  // Combine all permissions: wireInheritedPermissions → wirePermissions → funcInheritedPermissions → funcPermissions
@@ -361,9 +362,9 @@ export const runPermissions = async (
361
362
  for (const permission of allPermissions) {
362
363
  const result = await verifyPermissions(
363
364
  typeof permission === 'function' ? { permission } : permission,
364
- allServices,
365
+ services,
365
366
  data,
366
- session
367
+ wire
367
368
  )
368
369
  if (result) {
369
370
  permissioned = true
@@ -371,7 +372,7 @@ export const runPermissions = async (
371
372
  }
372
373
  }
373
374
  if (!permissioned) {
374
- allServices.logger.debug('Permission denied - combined permissions')
375
+ services.logger.debug('Permission denied - combined permissions')
375
376
  throw new ForbiddenError('Permission denied')
376
377
  }
377
378
  }
@@ -21,7 +21,7 @@ import {
21
21
  CorePikkuPermission,
22
22
  } from './function/functions.types.js'
23
23
  import {
24
- queueWorkersMeta,
24
+ QueueWorkersMeta,
25
25
  CoreQueueWorker,
26
26
  } from './wirings/queue/queue.types.js'
27
27
  import {
@@ -33,6 +33,10 @@ import {
33
33
  MCPPromptMeta,
34
34
  } from './wirings/mcp/mcp.types.js'
35
35
  import { CLIMeta, CLIProgramState } from './wirings/cli/cli.types.js'
36
+ import {
37
+ CoreWorkflow,
38
+ WorkflowsMeta,
39
+ } from './wirings/workflow/workflow.types.js'
36
40
 
37
41
  interface PikkuState {
38
42
  function: {
@@ -65,7 +69,11 @@ interface PikkuState {
65
69
  }
66
70
  queue: {
67
71
  registrations: Map<string, CoreQueueWorker>
68
- meta: queueWorkersMeta
72
+ meta: QueueWorkersMeta
73
+ }
74
+ workflows: {
75
+ registrations: Map<string, CoreWorkflow>
76
+ meta: WorkflowsMeta
69
77
  }
70
78
  mcp: {
71
79
  resources: Map<string, CoreMCPResource>
@@ -166,6 +174,10 @@ export const resetPikkuState = () => {
166
174
  registrations: new Map(),
167
175
  meta: {},
168
176
  },
177
+ workflows: {
178
+ registrations: new Map(),
179
+ meta: {},
180
+ },
169
181
  mcp: {
170
182
  resources: new Map(),
171
183
  resourcesMeta: {} as MCPResourceMeta,
@@ -10,6 +10,7 @@ export * from './secret-service.js'
10
10
  export * from './variables-service.js'
11
11
  export * from './schema-service.js'
12
12
  export * from './user-session-service.js'
13
+ export * from './scheduler-service.js'
13
14
 
14
15
  // Local implementations
15
16
  export * from './local-secrets.js'
@@ -0,0 +1,76 @@
1
+ import { CoreUserSession } from '../types/core.types.js'
2
+
3
+ /**
4
+ * Minimal metadata for listing scheduled tasks
5
+ */
6
+ export interface ScheduledTaskSummary {
7
+ /** Unique task ID */
8
+ taskId: string
9
+ /** RPC function name to invoke */
10
+ rpcName: string
11
+ /** Scheduled execution time */
12
+ scheduledFor: Date
13
+ }
14
+
15
+ /**
16
+ * Full metadata for a scheduled task retrieved from the queue
17
+ */
18
+ export interface ScheduledTaskInfo extends ScheduledTaskSummary {
19
+ /** Data to pass to the RPC function */
20
+ data?: any
21
+ /** User session */
22
+ session?: CoreUserSession
23
+ /** Task status */
24
+ status?: 'scheduled' | 'active' | 'completed' | 'failed'
25
+ }
26
+
27
+ /**
28
+ * Abstract scheduler service for persistent scheduled task management
29
+ * Implementations use queue backends (pg-boss, BullMQ) for distributed scheduling
30
+ */
31
+ export abstract class SchedulerService {
32
+ /**
33
+ * Initialize the scheduler service
34
+ */
35
+ abstract init(): Promise<void>
36
+
37
+ /**
38
+ * Schedule a one-off delayed RPC call
39
+ * @param delay - Delay before execution (number in milliseconds or duration string like "5h", "30m")
40
+ * @param rpcName - RPC function name to invoke
41
+ * @param data - Data to pass to the RPC function
42
+ * @param session - Optional user session
43
+ * @returns Task ID
44
+ */
45
+ abstract scheduleRPC(
46
+ delay: number | string,
47
+ rpcName: string,
48
+ data?: any,
49
+ session?: CoreUserSession
50
+ ): Promise<string>
51
+
52
+ /**
53
+ * Unschedule a task by ID
54
+ * @param taskId - Task ID
55
+ * @returns Success status
56
+ */
57
+ abstract unschedule(taskId: string): Promise<boolean>
58
+
59
+ /**
60
+ * Get a scheduled task by ID with full details
61
+ * @param taskId - Task ID
62
+ * @returns Task info or null if not found
63
+ */
64
+ abstract getTask(taskId: string): Promise<ScheduledTaskInfo | null>
65
+
66
+ /**
67
+ * Get all scheduled tasks with minimal info
68
+ * @returns Array of task summaries with taskId, rpcName, and schedule
69
+ */
70
+ abstract getAllTasks(): Promise<ScheduledTaskSummary[]>
71
+
72
+ /**
73
+ * Close any open connections
74
+ */
75
+ abstract close(): Promise<void>
76
+ }
@@ -1,18 +1,21 @@
1
1
  import { ChannelStore } from '../wirings/channel/channel-store.js'
2
2
  import { CoreUserSession } from '../types/core.types.js'
3
3
 
4
- export interface UserSessionService<UserSession extends CoreUserSession> {
4
+ export interface SessionService<UserSession extends CoreUserSession> {
5
5
  sessionChanged: boolean
6
+ initial: UserSession | undefined
6
7
  setInitial(session: UserSession): void
8
+ freezeInitial(): UserSession | undefined
7
9
  set(session: UserSession): Promise<void> | void
8
10
  clear(): Promise<void> | void
9
- get(): Promise<UserSession | undefined> | UserSession | undefined
11
+ get(): Promise<UserSession> | UserSession | undefined
10
12
  }
11
13
 
12
- export class PikkuUserSessionService<UserSession extends CoreUserSession>
13
- implements UserSessionService<UserSession>
14
+ export class PikkuSessionService<UserSession extends CoreUserSession>
15
+ implements SessionService<UserSession>
14
16
  {
15
17
  public sessionChanged = false
18
+ public initial: UserSession | undefined
16
19
  private session: UserSession | undefined
17
20
  constructor(
18
21
  private channelStore?: ChannelStore<unknown, unknown, UserSession>,
@@ -27,6 +30,13 @@ export class PikkuUserSessionService<UserSession extends CoreUserSession>
27
30
  this.session = session
28
31
  }
29
32
 
33
+ public freezeInitial() {
34
+ if (this.initial === undefined) {
35
+ this.initial = this.session
36
+ }
37
+ return this.initial
38
+ }
39
+
30
40
  public set(session: UserSession) {
31
41
  this.sessionChanged = true
32
42
  this.session = session
package/src/time-utils.ts CHANGED
@@ -30,3 +30,78 @@ export const getRelativeTimeOffsetFromNow = (
30
30
  ): Date => {
31
31
  return new Date(Date.now() + getRelativeTimeOffset(relativeTime))
32
32
  }
33
+
34
+ /**
35
+ * Get duration in milliseconds from a string or number
36
+ * @param duration
37
+ * @returns
38
+ */
39
+ export const getDurationInMilliseconds = (
40
+ duration: string | number
41
+ ): number => {
42
+ if (typeof duration === 'number') {
43
+ return duration
44
+ }
45
+ return parseDurationString(duration)
46
+ }
47
+
48
+ /**
49
+ * Parse a duration string to milliseconds
50
+ * Supports formats like: '2s', '5s', '5sec', '5seconds', '5m', '5min', '5minutes', '1h', '1hour', '2d', '2day', '1w', '1week'
51
+ *
52
+ * @param duration - Duration string (e.g., '2s', '5min', '2hours', '1day')
53
+ * @returns Duration in milliseconds
54
+ */
55
+ export const parseDurationString = (duration: string): number => {
56
+ const match = duration.match(
57
+ /^(\d+)(ms|milliseconds?|s|sec|seconds?|m|min|minutes?|h|hour|hours?|d|day|days?|w|week|weeks?|y|year|years?)$/
58
+ )
59
+
60
+ if (!match) {
61
+ throw new Error(
62
+ `Invalid duration format: ${duration}. Use formats like '2s', '5s', '5min', '1hour', '2days', '1week'`
63
+ )
64
+ }
65
+
66
+ const value = parseInt(match[1], 10)
67
+ const unitStr = match[2]
68
+
69
+ // Handle milliseconds specially
70
+ if (
71
+ unitStr === 'ms' ||
72
+ unitStr === 'millisecond' ||
73
+ unitStr === 'milliseconds'
74
+ ) {
75
+ return value
76
+ }
77
+
78
+ // Map string variations to TimeUnit
79
+ let unit: TimeUnit
80
+ if (
81
+ unitStr === 's' ||
82
+ unitStr === 'sec' ||
83
+ unitStr === 'second' ||
84
+ unitStr === 'seconds'
85
+ ) {
86
+ unit = 'second'
87
+ } else if (
88
+ unitStr === 'm' ||
89
+ unitStr === 'min' ||
90
+ unitStr === 'minute' ||
91
+ unitStr === 'minutes'
92
+ ) {
93
+ unit = 'minute'
94
+ } else if (unitStr === 'h' || unitStr === 'hour' || unitStr === 'hours') {
95
+ unit = 'hour'
96
+ } else if (unitStr === 'd' || unitStr === 'day' || unitStr === 'days') {
97
+ unit = 'day'
98
+ } else if (unitStr === 'w' || unitStr === 'week' || unitStr === 'weeks') {
99
+ unit = 'week'
100
+ } else if (unitStr === 'y' || unitStr === 'year' || unitStr === 'years') {
101
+ unit = 'year'
102
+ } else {
103
+ throw new Error(`Unknown time unit: ${unitStr}`)
104
+ }
105
+
106
+ return getRelativeTimeOffset({ value, unit })
107
+ }
@@ -3,23 +3,30 @@ import { VariablesService } from '../services/variables-service.js'
3
3
  import { SchemaService } from '../services/schema-service.js'
4
4
  import { JWTService } from '../services/jwt-service.js'
5
5
  import { PikkuHTTP } from '../wirings/http/http.types.js'
6
- import { UserSessionService } from '../services/user-session-service.js'
6
+ import { SessionService } from '../services/user-session-service.js'
7
7
  import { PikkuChannel } from '../wirings/channel/channel.types.js'
8
8
  import { PikkuRPC } from '../wirings/rpc/rpc-types.js'
9
9
  import { PikkuMCP } from '../wirings/mcp/mcp.types.js'
10
10
  import { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js'
11
- import { PikkuQueue } from '../wirings/queue/queue.types.js'
11
+ import { PikkuQueue, QueueService } from '../wirings/queue/queue.types.js'
12
12
  import { PikkuCLI } from '../wirings/cli/cli.types.js'
13
+ import {
14
+ PikkuWorkflowWire,
15
+ WorkflowService,
16
+ WorkflowServiceConfig,
17
+ WorkflowStepWire,
18
+ } from '../wirings/workflow/workflow.types.js'
19
+ import { SchedulerService } from '../services/scheduler-service.js'
13
20
 
14
- export enum PikkuWiringTypes {
15
- http = 'http',
16
- scheduler = 'scheduler',
17
- channel = 'channel',
18
- rpc = 'rpc',
19
- queue = 'queue',
20
- mcp = 'mcp',
21
- cli = 'cli',
22
- }
21
+ export type PikkuWiringTypes =
22
+ | 'http'
23
+ | 'scheduler'
24
+ | 'channel'
25
+ | 'rpc'
26
+ | 'queue'
27
+ | 'mcp'
28
+ | 'cli'
29
+ | 'workflow'
23
30
 
24
31
  export interface FunctionServicesMeta {
25
32
  optimized: boolean
@@ -73,20 +80,22 @@ export type FunctionRuntimeMeta = {
73
80
  inputSchemaName: string | null
74
81
  outputSchemaName: string | null
75
82
  expose?: boolean
83
+ internal?: boolean
76
84
  }
77
85
 
78
86
  export type FunctionMeta = FunctionRuntimeMeta &
79
- Partial<{
80
- name: string
81
- services: FunctionServicesMeta
82
- inputs: string[] | null
83
- outputs: string[] | null
84
- tags: string[]
85
- docs: PikkuDocs
86
- isDirectFunction: boolean // true if it's pikkuFunc(fn), false if it's pikkuFunc({ func: fn })
87
- middleware: MiddlewareMetadata[] // Function-level middleware
88
- permissions: PermissionMetadata[] // Function-level permissions
89
- }>
87
+ Partial<
88
+ {
89
+ name: string
90
+ services: FunctionServicesMeta
91
+ usedWires: string[]
92
+ inputs: string[] | null
93
+ outputs: string[] | null
94
+ middleware: MiddlewareMetadata[]
95
+ permissions: PermissionMetadata[]
96
+ isDirectFunction: boolean
97
+ } & CommonWireMeta
98
+ >
90
99
 
91
100
  export type FunctionsRuntimeMeta = Record<string, FunctionRuntimeMeta>
92
101
  export type FunctionsMeta = Record<string, FunctionMeta>
@@ -137,6 +146,8 @@ export type CoreConfig<Config extends Record<string, unknown> = {}> = {
137
146
  logLevel?: LogLevel
138
147
  /** Secrets used by the application (optional). */
139
148
  secrets?: {}
149
+
150
+ workflow?: WorkflowServiceConfig
140
151
  } & Config
141
152
 
142
153
  /**
@@ -158,32 +169,53 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
158
169
  logger: Logger
159
170
  /** The variable service to be used */
160
171
  variables: VariablesService
172
+ /** The workflow orchestrator service */
173
+ workflowService?: WorkflowService
174
+ /** The queue service */
175
+ queueService?: QueueService
176
+ /** The scheduler service */
177
+ schedulerService?: SchedulerService
161
178
  }
162
179
 
163
180
  /**
164
- * Represents different forms of interaction within Pikku and the outside world.
181
+ * Represents different forms of wire within Pikku and the outside world.
165
182
  */
166
- export type PikkuInteraction<In = unknown, Out = unknown> = Partial<{
183
+ export type PikkuWire<
184
+ In = unknown,
185
+ Out = unknown,
186
+ HasInitialSession extends boolean = false,
187
+ UserSession extends CoreUserSession = CoreUserSession,
188
+ TypedRPC extends PikkuRPC = PikkuRPC,
189
+ IsChannel extends true | null = null,
190
+ MCPTools extends string | never = never,
191
+ TypedWorkflow extends PikkuWorkflowWire | never = PikkuWorkflowWire,
192
+ > = Partial<{
167
193
  http: PikkuHTTP<In>
168
- mcp: PikkuMCP
169
- rpc: PikkuRPC
170
- channel: PikkuChannel<unknown, Out>
194
+ mcp: PikkuMCP<MCPTools>
195
+ rpc: TypedRPC
196
+ channel: [IsChannel] extends [null]
197
+ ? PikkuChannel<unknown, Out>
198
+ : PikkuChannel<unknown, Out> | undefined
171
199
  scheduledTask: PikkuScheduledTask
172
200
  queue: PikkuQueue
173
201
  cli: PikkuCLI
202
+ workflow: TypedWorkflow
203
+ workflowStep: WorkflowStepWire
204
+ initialSession: HasInitialSession extends true
205
+ ? UserSession
206
+ : UserSession | undefined
207
+ session: SessionService<UserSession>
174
208
  }>
175
209
 
176
210
  /**
177
- * A function that can wrap an interaction and be called before or after
211
+ * A function that can wrap an wire and be called before or after
178
212
  */
179
213
  export type CorePikkuMiddleware<
180
214
  SingletonServices extends CoreSingletonServices = CoreSingletonServices,
181
215
  UserSession extends CoreUserSession = CoreUserSession,
182
216
  > = (
183
- services: SingletonServices & {
184
- userSession: UserSessionService<UserSession>
185
- },
186
- interactions: PikkuInteraction,
217
+ services: SingletonServices,
218
+ wires: PikkuWire<unknown, unknown, false, UserSession>,
187
219
  next: () => Promise<void>
188
220
  ) => Promise<void>
189
221
 
@@ -235,7 +267,7 @@ export type CorePikkuMiddlewareGroup<
235
267
  * ```typescript
236
268
  * // Direct function syntax
237
269
  * export const logMiddleware = pikkuMiddleware(
238
- * async ({ logger }, _interaction, next) => {
270
+ * async ({ logger }, next) => {
239
271
  * logger.info('Request started')
240
272
  * await next()
241
273
  * }
@@ -245,7 +277,7 @@ export type CorePikkuMiddlewareGroup<
245
277
  * export const logMiddleware = pikkuMiddleware({
246
278
  * name: 'Request Logger',
247
279
  * description: 'Logs request information',
248
- * func: async ({ logger }, _interaction, next) => {
280
+ * func: async ({ logger }, next) => {
249
281
  * logger.info('Request started')
250
282
  * await next()
251
283
  * }
@@ -273,7 +305,7 @@ export const pikkuMiddleware = <
273
305
  * message,
274
306
  * level = 'info'
275
307
  * }) => {
276
- * return pikkuMiddleware(async ({ logger }, _interaction, next) => {
308
+ * return pikkuMiddleware(async ({ logger }, next) => {
277
309
  * logger[level](message)
278
310
  * await next()
279
311
  * })
@@ -287,20 +319,15 @@ export const pikkuMiddlewareFactory = <In = any>(
287
319
  }
288
320
 
289
321
  /**
290
- * Represents the core services used by Pikku, including singleton services and the request/response interaction.
322
+ * Represents the core services used by Pikku, including singleton services.
291
323
  */
292
- export type CoreServices<
293
- SingletonServices = CoreSingletonServices,
294
- UserSession extends CoreUserSession = CoreUserSession,
295
- > = SingletonServices &
296
- PikkuInteraction & {
297
- userSession?: UserSessionService<UserSession>
298
- }
324
+ export type CoreServices<SingletonServices = CoreSingletonServices> =
325
+ SingletonServices
299
326
 
300
- export type SessionServices<
327
+ export type WireServices<
301
328
  SingletonServices extends CoreSingletonServices = CoreSingletonServices,
302
329
  Services = CoreServices<SingletonServices>,
303
- > = Omit<Services, keyof SingletonServices | keyof PikkuInteraction | 'session'>
330
+ > = Omit<Services, keyof SingletonServices | 'session'>
304
331
 
305
332
  /**
306
333
  * Defines a function type for creating singleton services from the given configuration.
@@ -316,16 +343,15 @@ export type CreateSingletonServices<
316
343
  /**
317
344
  * Defines a function type for creating session-specific services.
318
345
  */
319
- export type CreateSessionServices<
346
+ export type CreateWireServices<
320
347
  SingletonServices extends CoreSingletonServices = CoreSingletonServices,
321
348
  Services extends
322
349
  CoreServices<SingletonServices> = CoreServices<SingletonServices>,
323
350
  UserSession extends CoreUserSession = CoreUserSession,
324
351
  > = (
325
352
  services: SingletonServices,
326
- interaction: PikkuInteraction,
327
- session: UserSession | undefined
328
- ) => Promise<SessionServices<Services, SingletonServices>>
353
+ wire: PikkuWire<unknown, unknown, false, UserSession>
354
+ ) => Promise<WireServices<Services, SingletonServices>>
329
355
 
330
356
  /**
331
357
  * Defines a function type for creating config.
@@ -338,9 +364,24 @@ export type CreateConfig<
338
364
  /**
339
365
  * Represents the documentation for a route, including summary, description, tags, and errors.
340
366
  */
341
- export type PikkuDocs = {
367
+ export type CommonWireMeta = {
368
+ pikkuFuncName: string
369
+
370
+ tags?: string[]
342
371
  summary?: string
343
372
  description?: string
344
- tags?: string[]
345
373
  errors?: string[]
374
+
375
+ middleware?: MiddlewareMetadata[]
376
+ permissions?: PermissionMetadata[]
377
+ }
378
+
379
+ /**
380
+ * Serialized error for storage
381
+ */
382
+ export interface SerializedError {
383
+ message: string
384
+ stack?: string
385
+ code?: string
386
+ [key: string]: any
346
387
  }
package/src/utils.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import { Logger } from './services/logger.js'
2
2
 
3
- // TODO: SessionServices probably needs it's own type
3
+ // TODO: WireServices probably needs it's own type
4
4
  // but is an issue for the future and will be tackled
5
5
  // with dependency injection
6
- export const closeSessionServices = async (
6
+ export const closeWireServices = async (
7
7
  logger: Logger,
8
- sessionServices: Record<string, any>
8
+ wireServices: Record<string, any>
9
9
  ) => {
10
10
  await Promise.all(
11
- Object.values(sessionServices).map(async (service) => {
11
+ Object.values(wireServices).map(async (service) => {
12
12
  if (service?.close) {
13
13
  try {
14
14
  await service.close()
@@ -1,8 +1,4 @@
1
- import {
2
- CoreServices,
3
- PikkuWiringTypes,
4
- CorePikkuMiddleware,
5
- } from '../../types/core.types.js'
1
+ import { CoreServices, CorePikkuMiddleware } from '../../types/core.types.js'
6
2
  import { CoreChannel, ChannelMessageMeta } from './channel.types.js'
7
3
  import { combineMiddleware, runMiddleware } from '../../middleware-runner.js'
8
4
  import { runPikkuFuncDirectly } from '../../function/function-runner.js'
@@ -49,7 +45,7 @@ export const runChannelLifecycleWithMiddleware = async ({
49
45
 
50
46
  // Use combineMiddleware to properly resolve metadata + inline middleware
51
47
  const allMiddleware = combineMiddleware(
52
- PikkuWiringTypes.channel,
48
+ 'channel',
53
49
  `${channelConfig.name}:${lifecycleType}`,
54
50
  {
55
51
  wireInheritedMiddleware: meta.middleware,
@@ -61,7 +57,8 @@ export const runChannelLifecycleWithMiddleware = async ({
61
57
  const runLifecycle = async () => {
62
58
  return await runPikkuFuncDirectly(
63
59
  meta.pikkuFuncName,
64
- { ...services, channel },
60
+ services,
61
+ { channel },
65
62
  data
66
63
  )
67
64
  }