@pikku/core 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/dist/errors/error-handler.js +3 -3
  3. package/dist/errors/errors.d.ts +1 -1
  4. package/dist/errors/errors.js +3 -3
  5. package/dist/function/function-runner.d.ts +8 -8
  6. package/dist/function/function-runner.js +88 -23
  7. package/dist/function/functions.types.d.ts +104 -33
  8. package/dist/function/functions.types.js +50 -7
  9. package/dist/handle-error.d.ts +1 -1
  10. package/dist/handle-error.js +1 -1
  11. package/dist/index.d.ts +6 -2
  12. package/dist/index.js +5 -2
  13. package/dist/middleware/auth-apikey.d.ts +1 -1
  14. package/dist/middleware/auth-apikey.js +3 -3
  15. package/dist/middleware/auth-bearer.d.ts +1 -1
  16. package/dist/middleware/auth-bearer.js +3 -3
  17. package/dist/middleware/auth-cookie.d.ts +1 -1
  18. package/dist/middleware/auth-cookie.js +5 -5
  19. package/dist/middleware/timeout.d.ts +1 -1
  20. package/dist/middleware/timeout.js +3 -2
  21. package/dist/middleware-runner.d.ts +6 -20
  22. package/dist/middleware-runner.js +19 -20
  23. package/dist/permissions.d.ts +6 -89
  24. package/dist/permissions.js +24 -81
  25. package/dist/pikku-state.d.ts +32 -104
  26. package/dist/pikku-state.js +140 -66
  27. package/dist/schema.d.ts +8 -6
  28. package/dist/schema.js +25 -13
  29. package/dist/services/user-session-service.d.ts +7 -3
  30. package/dist/services/user-session-service.js +8 -1
  31. package/dist/services/workflow-service.d.ts +38 -0
  32. package/dist/services/workflow-service.js +1 -0
  33. package/dist/types/core.types.d.ts +40 -41
  34. package/dist/types/core.types.js +4 -15
  35. package/dist/types/state.types.d.ts +135 -0
  36. package/dist/types/state.types.js +1 -0
  37. package/dist/utils.d.ts +9 -1
  38. package/dist/utils.js +48 -3
  39. package/dist/wirings/channel/channel-common.js +2 -3
  40. package/dist/wirings/channel/channel-handler.d.ts +3 -2
  41. package/dist/wirings/channel/channel-handler.js +7 -10
  42. package/dist/wirings/channel/channel-runner.d.ts +2 -2
  43. package/dist/wirings/channel/channel-runner.js +5 -5
  44. package/dist/wirings/channel/channel.types.d.ts +10 -5
  45. package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
  46. package/dist/wirings/channel/local/local-channel-runner.js +19 -26
  47. package/dist/wirings/channel/log-channels.js +1 -1
  48. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
  49. package/dist/wirings/channel/serverless/serverless-channel-runner.js +43 -48
  50. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
  51. package/dist/wirings/cli/cli-runner.d.ts +5 -5
  52. package/dist/wirings/cli/cli-runner.js +20 -38
  53. package/dist/wirings/cli/cli.types.d.ts +16 -11
  54. package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
  55. package/dist/wirings/forge-node/forge-node.types.js +38 -0
  56. package/dist/wirings/forge-node/index.d.ts +1 -0
  57. package/dist/wirings/forge-node/index.js +1 -0
  58. package/dist/wirings/http/http-runner.d.ts +8 -8
  59. package/dist/wirings/http/http-runner.js +46 -51
  60. package/dist/wirings/http/http.types.d.ts +19 -11
  61. package/dist/wirings/http/log-http-routes.js +1 -1
  62. package/dist/wirings/http/routers/path-to-regex.js +2 -2
  63. package/dist/wirings/mcp/mcp-runner.d.ts +2 -2
  64. package/dist/wirings/mcp/mcp-runner.js +33 -40
  65. package/dist/wirings/mcp/mcp.types.d.ts +6 -0
  66. package/dist/wirings/queue/queue-runner.d.ts +3 -3
  67. package/dist/wirings/queue/queue-runner.js +13 -23
  68. package/dist/wirings/queue/queue.types.d.ts +4 -11
  69. package/dist/wirings/rpc/index.d.ts +1 -1
  70. package/dist/wirings/rpc/index.js +1 -1
  71. package/dist/wirings/rpc/rpc-runner.d.ts +17 -16
  72. package/dist/wirings/rpc/rpc-runner.js +98 -61
  73. package/dist/wirings/rpc/rpc-types.d.ts +7 -0
  74. package/dist/wirings/scheduler/log-schedulers.js +1 -1
  75. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -3
  76. package/dist/wirings/scheduler/scheduler-runner.js +18 -29
  77. package/dist/wirings/scheduler/scheduler.types.d.ts +3 -8
  78. package/dist/wirings/trigger/index.d.ts +2 -0
  79. package/dist/wirings/trigger/index.js +2 -0
  80. package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
  81. package/dist/wirings/trigger/trigger-runner.js +57 -0
  82. package/dist/wirings/trigger/trigger.types.d.ts +42 -0
  83. package/dist/wirings/trigger/trigger.types.js +1 -0
  84. package/dist/wirings/workflow/dsl/index.d.ts +5 -0
  85. package/dist/wirings/workflow/dsl/index.js +4 -0
  86. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
  87. package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
  88. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
  89. package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
  90. package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
  91. package/dist/wirings/workflow/graph/graph-node.js +58 -0
  92. package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
  93. package/dist/wirings/workflow/graph/graph-runner.js +452 -0
  94. package/dist/wirings/workflow/graph/index.d.ts +3 -0
  95. package/dist/wirings/workflow/graph/index.js +3 -0
  96. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
  97. package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
  98. package/dist/wirings/workflow/index.d.ts +7 -3
  99. package/dist/wirings/workflow/index.js +6 -3
  100. package/dist/wirings/workflow/pikku-workflow-service.d.ts +108 -10
  101. package/dist/wirings/workflow/pikku-workflow-service.js +274 -165
  102. package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
  103. package/dist/wirings/workflow/wire-workflow.js +53 -0
  104. package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
  105. package/dist/wirings/workflow/workflow-utils.js +66 -0
  106. package/dist/wirings/workflow/workflow.types.d.ts +135 -128
  107. package/package.json +11 -2
  108. package/src/errors/error-handler.ts +3 -3
  109. package/src/errors/errors.ts +3 -3
  110. package/src/factory-functions.test.ts +9 -36
  111. package/src/function/function-runner.test.ts +58 -69
  112. package/src/function/function-runner.ts +130 -37
  113. package/src/function/functions.types.ts +193 -54
  114. package/src/handle-error.ts +1 -1
  115. package/src/index.ts +10 -5
  116. package/src/middleware/auth-apikey.test.ts +360 -0
  117. package/src/middleware/auth-apikey.ts +3 -7
  118. package/src/middleware/auth-bearer.test.ts +447 -0
  119. package/src/middleware/auth-bearer.ts +27 -33
  120. package/src/middleware/auth-cookie.test.ts +525 -0
  121. package/src/middleware/auth-cookie.ts +6 -6
  122. package/src/middleware/timeout.ts +4 -2
  123. package/src/middleware-runner.test.ts +58 -127
  124. package/src/middleware-runner.ts +29 -25
  125. package/src/permissions.test.ts +68 -130
  126. package/src/permissions.ts +41 -100
  127. package/src/pikku-state.ts +156 -201
  128. package/src/schema.ts +42 -13
  129. package/src/services/user-session-service.ts +14 -4
  130. package/src/services/workflow-service.ts +74 -0
  131. package/src/types/core.types.ts +79 -58
  132. package/src/types/state.types.ts +195 -0
  133. package/src/utils.ts +59 -4
  134. package/src/wirings/channel/channel-common.ts +4 -7
  135. package/src/wirings/channel/channel-handler.ts +17 -23
  136. package/src/wirings/channel/channel-runner.ts +7 -7
  137. package/src/wirings/channel/channel.types.ts +14 -11
  138. package/src/wirings/channel/local/local-channel-runner.test.ts +8 -4
  139. package/src/wirings/channel/local/local-channel-runner.ts +23 -38
  140. package/src/wirings/channel/log-channels.ts +1 -1
  141. package/src/wirings/channel/serverless/serverless-channel-runner.ts +53 -79
  142. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
  143. package/src/wirings/cli/cli-runner.test.ts +26 -26
  144. package/src/wirings/cli/cli-runner.ts +34 -71
  145. package/src/wirings/cli/cli.types.ts +23 -16
  146. package/src/wirings/forge-node/forge-node.types.ts +135 -0
  147. package/src/wirings/forge-node/index.ts +1 -0
  148. package/src/wirings/http/http-runner.test.ts +10 -10
  149. package/src/wirings/http/http-runner.ts +56 -66
  150. package/src/wirings/http/http.types.ts +19 -14
  151. package/src/wirings/http/log-http-routes.ts +1 -1
  152. package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
  153. package/src/wirings/http/routers/path-to-regex.ts +2 -2
  154. package/src/wirings/mcp/mcp-runner.ts +44 -69
  155. package/src/wirings/mcp/mcp.types.ts +6 -0
  156. package/src/wirings/queue/queue-runner.test.ts +641 -0
  157. package/src/wirings/queue/queue-runner.ts +16 -38
  158. package/src/wirings/queue/queue.types.ts +4 -11
  159. package/src/wirings/rpc/index.ts +1 -1
  160. package/src/wirings/rpc/rpc-runner.ts +129 -77
  161. package/src/wirings/rpc/rpc-types.ts +8 -0
  162. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  163. package/src/wirings/scheduler/scheduler-runner.test.ts +627 -0
  164. package/src/wirings/scheduler/scheduler-runner.ts +29 -55
  165. package/src/wirings/scheduler/scheduler.types.ts +3 -9
  166. package/src/wirings/trigger/index.ts +2 -0
  167. package/src/wirings/trigger/trigger-runner.ts +96 -0
  168. package/src/wirings/trigger/trigger.types.ts +56 -0
  169. package/src/wirings/workflow/dsl/index.ts +30 -0
  170. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
  171. package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
  172. package/src/wirings/workflow/graph/graph-node.ts +227 -0
  173. package/src/wirings/workflow/graph/graph-runner.ts +694 -0
  174. package/src/wirings/workflow/graph/index.ts +3 -0
  175. package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
  176. package/src/wirings/workflow/index.ts +60 -12
  177. package/src/wirings/workflow/pikku-workflow-service.ts +401 -195
  178. package/src/wirings/workflow/wire-workflow.ts +94 -0
  179. package/src/wirings/workflow/workflow-utils.ts +120 -0
  180. package/src/wirings/workflow/workflow.types.ts +167 -188
  181. package/tsconfig.tsbuildinfo +1 -1
  182. package/dist/wirings/workflow/workflow-runner.d.ts +0 -35
  183. package/dist/wirings/workflow/workflow-runner.js +0 -68
  184. package/src/wirings/workflow/workflow-runner.ts +0 -85
@@ -0,0 +1,53 @@
1
+ import { pikkuState } from '../../pikku-state.js';
2
+ /**
3
+ * Type guard for DSL workflow definition
4
+ */
5
+ function isWorkflowDefinitionFunc(def) {
6
+ return 'func' in def;
7
+ }
8
+ /**
9
+ * Type guard for graph workflow definition
10
+ */
11
+ function isWorkflowDefinitionGraph(def) {
12
+ return 'graph' in def;
13
+ }
14
+ /**
15
+ * Wire a workflow with triggers.
16
+ * Accepts either a DSL function (func) or a graph definition (graph).
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // DSL workflow
21
+ * wireWorkflow({
22
+ * wires: { http: { route: '/start', method: 'post' } },
23
+ * func: myWorkflowFunc,
24
+ * })
25
+ *
26
+ * // Graph workflow
27
+ * wireWorkflow({
28
+ * wires: { http: { route: '/graph-start', method: 'post' } },
29
+ * graph: myGraphWorkflow,
30
+ * })
31
+ * ```
32
+ */
33
+ export function wireWorkflow(definition) {
34
+ if (isWorkflowDefinitionFunc(definition)) {
35
+ // DSL workflow - store wiring for later registration by inspector
36
+ const wirings = pikkuState(null, 'workflows', 'wirings');
37
+ // The wiring will be matched to the function by the inspector
38
+ // Store the func reference and wires
39
+ wirings.set(definition.func, {
40
+ wires: definition.wires,
41
+ func: definition.func,
42
+ });
43
+ }
44
+ else if (isWorkflowDefinitionGraph(definition)) {
45
+ // Graph workflow - store for registration
46
+ const graphWirings = pikkuState(null, 'workflows', 'graphWirings');
47
+ // Store the graph reference and wires
48
+ graphWirings.set(definition.graph, {
49
+ wires: definition.wires,
50
+ graph: definition.graph,
51
+ });
52
+ }
53
+ }
@@ -0,0 +1,23 @@
1
+ import { PikkuWire, CreateWireServices, CoreSingletonServices, CoreServices, CoreUserSession } from '../../types/core.types.js';
2
+ import { HTTPWiringMeta } from '../http/http.types.js';
3
+ /**
4
+ * Result of finding a workflow by HTTP wire
5
+ */
6
+ export interface WorkflowHttpMatch {
7
+ workflowName: string;
8
+ startNode?: string;
9
+ }
10
+ /**
11
+ * Find workflow name by matching route and method against workflow wires
12
+ */
13
+ export declare const findWorkflowByHttpWire: (route: string, method: string) => WorkflowHttpMatch | undefined;
14
+ /**
15
+ * Start a workflow triggered by an HTTP wire
16
+ * The workflow is responsible for handling the HTTP response
17
+ */
18
+ export declare const startWorkflowByHttpWire: (singletonServices: CoreSingletonServices, createWireServices: CreateWireServices<CoreSingletonServices, CoreServices<CoreSingletonServices>, CoreUserSession> | undefined, matchedRoute: {
19
+ matchedPath: any;
20
+ params: any;
21
+ route: any;
22
+ meta: HTTPWiringMeta;
23
+ }, wire: PikkuWire) => Promise<void>;
@@ -0,0 +1,66 @@
1
+ import { pikkuState } from '../../pikku-state.js';
2
+ import { NotFoundError } from '../../errors/errors.js';
3
+ import { ContextAwareRPCService } from '../rpc/rpc-runner.js';
4
+ /**
5
+ * Find workflow name by matching route and method against workflow wires
6
+ */
7
+ export const findWorkflowByHttpWire = (route, method) => {
8
+ const wirings = pikkuState(null, 'workflows', 'wirings');
9
+ const graphWirings = pikkuState(null, 'workflows', 'graphWirings');
10
+ // Check DSL workflow wirings
11
+ for (const [, wiring] of wirings) {
12
+ const httpWires = wiring.wires?.http;
13
+ if (httpWires) {
14
+ const matchedWire = httpWires.find((w) => w.route === route && w.method === method);
15
+ if (matchedWire) {
16
+ const meta = pikkuState(null, 'workflows', 'meta');
17
+ for (const [name, workflowMeta] of Object.entries(meta)) {
18
+ if (workflowMeta.source !== 'graph') {
19
+ const registrations = pikkuState(null, 'workflows', 'registrations');
20
+ if (registrations.has(name)) {
21
+ return { workflowName: name, startNode: matchedWire.startNode };
22
+ }
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ // Check graph workflow wirings
29
+ for (const [, wiring] of graphWirings) {
30
+ const httpWires = wiring.wires?.http;
31
+ if (httpWires) {
32
+ const matchedWire = httpWires.find((w) => w.route === route && w.method === method);
33
+ if (matchedWire) {
34
+ const meta = pikkuState(null, 'workflows', 'meta');
35
+ for (const [name, workflowMeta] of Object.entries(meta)) {
36
+ if (workflowMeta.source === 'graph') {
37
+ return { workflowName: name, startNode: matchedWire.startNode };
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ return undefined;
44
+ };
45
+ /**
46
+ * Start a workflow triggered by an HTTP wire
47
+ * The workflow is responsible for handling the HTTP response
48
+ */
49
+ export const startWorkflowByHttpWire = async (singletonServices, createWireServices, matchedRoute, wire) => {
50
+ const { meta } = matchedRoute;
51
+ const match = findWorkflowByHttpWire(meta.route, meta.method);
52
+ if (!match) {
53
+ throw new NotFoundError(`No workflow found for route ${meta.method.toUpperCase()} ${meta.route}`);
54
+ }
55
+ const workflowService = singletonServices.workflowService;
56
+ if (!workflowService) {
57
+ throw new Error('WorkflowService not available');
58
+ }
59
+ const data = await wire.http.request.data();
60
+ const wireServices = createWireServices?.(singletonServices, wire);
61
+ const rpcService = new ContextAwareRPCService({ ...singletonServices, ...wireServices }, wire, {});
62
+ await workflowService.startWorkflow(match.workflowName, data, rpcService, {
63
+ inline: true,
64
+ startNode: match.startNode,
65
+ });
66
+ };
@@ -1,5 +1,8 @@
1
- import { PikkuDocs, MiddlewareMetadata, SerializedError, CoreSingletonServices, CreateSessionServices, CoreConfig } from '../../types/core.types.js';
1
+ import { SerializedError, CommonWireMeta } from '../../types/core.types.js';
2
2
  import { CorePikkuFunctionConfig } from '../../function/functions.types.js';
3
+ export type { WorkflowService } from '../../services/workflow-service.js';
4
+ export type { WorkflowStepOptions, WorkflowWireDoRPC, WorkflowWireDoInline, WorkflowWireSleep, InputSource, OutputBinding, RpcStepMeta, SimpleCondition, Condition, BranchCase, BranchStepMeta, ParallelGroupStepMeta, FanoutStepMeta, ReturnStepMeta, InlineStepMeta, SleepStepMeta, CancelStepMeta, SetStepMeta, SwitchCaseMeta, SwitchStepMeta, FilterStepMeta, ArrayPredicateStepMeta, WorkflowStepMeta, WorkflowStepWire, PikkuWorkflowWire, } from './dsl/workflow-dsl.types.js';
5
+ import type { WorkflowStepMeta } from './dsl/workflow-dsl.types.js';
3
6
  export interface WorkflowServiceConfig {
4
7
  retries: number;
5
8
  retryDelay: number;
@@ -7,6 +10,91 @@ export interface WorkflowServiceConfig {
7
10
  stepWorkerQueueName: string;
8
11
  sleeperRPCName: string;
9
12
  }
13
+ /**
14
+ * HTTP wire configuration for workflows
15
+ */
16
+ export interface WorkflowHTTPWire {
17
+ route: string;
18
+ method: 'get' | 'post' | 'put' | 'patch' | 'delete';
19
+ startNode: string;
20
+ }
21
+ /**
22
+ * Channel wire configuration for workflows
23
+ */
24
+ export interface WorkflowChannelWire {
25
+ name: string;
26
+ onConnect?: string;
27
+ onDisconnect?: string;
28
+ onMessage?: string;
29
+ }
30
+ /**
31
+ * Queue wire configuration for workflows
32
+ */
33
+ export interface WorkflowQueueWire {
34
+ name: string;
35
+ startNode: string;
36
+ }
37
+ /**
38
+ * CLI wire configuration for workflows
39
+ */
40
+ export interface WorkflowCliWire {
41
+ command: string;
42
+ startNode: string;
43
+ }
44
+ /**
45
+ * MCP wire configurations for workflows
46
+ */
47
+ export interface WorkflowMcpWires {
48
+ tool?: Array<{
49
+ name: string;
50
+ startNode: string;
51
+ }>;
52
+ prompt?: Array<{
53
+ name: string;
54
+ startNode: string;
55
+ }>;
56
+ resource?: Array<{
57
+ uri: string;
58
+ startNode: string;
59
+ }>;
60
+ }
61
+ /**
62
+ * Schedule wire configuration for workflows
63
+ */
64
+ export interface WorkflowScheduleWire {
65
+ cron?: string;
66
+ interval?: string;
67
+ startNode: string;
68
+ }
69
+ /**
70
+ * Trigger wire configuration for workflows
71
+ */
72
+ export interface WorkflowTriggerWire {
73
+ name: string;
74
+ startNode: string;
75
+ }
76
+ /**
77
+ * Wire configuration for workflows
78
+ * Defines how a workflow can be triggered
79
+ */
80
+ export interface WorkflowWires {
81
+ /** API entry point - node ID for startWorkflow() calls */
82
+ api?: string;
83
+ /** HTTP triggers */
84
+ http?: WorkflowHTTPWire[];
85
+ /** Channel triggers */
86
+ channel?: WorkflowChannelWire[];
87
+ /** Queue triggers */
88
+ queue?: WorkflowQueueWire[];
89
+ /** CLI triggers */
90
+ cli?: WorkflowCliWire[];
91
+ /** MCP triggers (tool, prompt, resource) */
92
+ mcp?: WorkflowMcpWires;
93
+ /** Schedule triggers */
94
+ schedule?: WorkflowScheduleWire[];
95
+ /** Named trigger wires */
96
+ trigger?: WorkflowTriggerWire[];
97
+ }
10
98
  /**
11
99
  * Workflow run status
12
100
  */
@@ -31,6 +119,8 @@ export interface WorkflowRun {
31
119
  output?: any;
32
120
  /** Error (if failed) */
33
121
  error?: SerializedError;
122
+ /** If true, workflow executes inline without queues */
123
+ inline?: boolean;
34
124
  /** Creation timestamp */
35
125
  createdAt: Date;
36
126
  /** Last update timestamp */
@@ -73,8 +163,6 @@ export interface StepState {
73
163
  export type CoreWorkflow<PikkuFunctionConfig extends CorePikkuFunctionConfig<any, any, any> = CorePikkuFunctionConfig<any, any, any>> = {
74
164
  /** Unique workflow name */
75
165
  name: string;
76
- /** Description of the workflow */
77
- description?: string;
78
166
  /** The workflow function */
79
167
  func: PikkuFunctionConfig;
80
168
  /** Middleware chain for this workflow */
@@ -83,93 +171,7 @@ export type CoreWorkflow<PikkuFunctionConfig extends CorePikkuFunctionConfig<any
83
171
  permissions?: PikkuFunctionConfig['permissions'];
84
172
  /** Tags for organization and filtering */
85
173
  tags?: string[];
86
- /** Documentation metadata */
87
- docs?: PikkuDocs;
88
- };
89
- /**
90
- * Workflow step options
91
- */
92
- export interface WorkflowStepOptions {
93
- /** Display name for logs/UI (optional, doesn't affect execution) */
94
- description?: string;
95
- /** Number of retry attempts for failed steps (only applies to local execution) */
96
- retries?: number;
97
- /** Delay between retry attempts (e.g., '1s', '2s', '2min') */
98
- retryDelay?: string | number;
99
- }
100
- /**
101
- * Type signature for workflow.do() RPC form - used by inspector
102
- */
103
- export type WorkflowInteractionDoRPC = <TOutput = any, TInput = any>(stepName: string, rpcName: string, data: TInput, options?: WorkflowStepOptions) => Promise<TOutput>;
104
- /**
105
- * Type signature for workflow.do() inline form - used by inspector
106
- */
107
- export type WorkflowInteractionDoInline = <T>(stepName: string, fn: () => Promise<T> | T, options?: WorkflowStepOptions) => Promise<T>;
108
- /**
109
- * Type signature for workflow.sleep() - used by inspector
110
- */
111
- export type WorkflowInteractionSleep = (stepName: string, duration: string) => Promise<void>;
112
- /**
113
- * Workflow step metadata (extracted by inspector)
114
- */
115
- export type WorkflowStepMeta = {
116
- /** RPC form - generates queue worker */
117
- type: 'rpc';
118
- /** Cache key (stepName from workflow.do) */
119
- stepName: string;
120
- /** RPC to invoke */
121
- rpcName: string;
122
- /** Display name */
123
- description?: string;
124
- /** Step options */
125
- options?: WorkflowStepOptions;
126
- } | {
127
- /** Inline form - local execution */
128
- type: 'inline';
129
- /** Cache key (stepName from workflow.do) */
130
- stepName: string;
131
- /** Display name */
132
- description?: string;
133
- /** Step options */
134
- options?: WorkflowStepOptions;
135
- } | {
136
- /** Sleep step */
137
- type: 'sleep';
138
- /** Cache key (stepName from workflow.sleep) */
139
- stepName: string;
140
- /** Sleep duration */
141
- duration: string | number;
142
174
  };
143
- /**
144
- * Workflow step interaction context for RPC functions
145
- * Provides step-level metadata including retry attempt tracking
146
- */
147
- export interface WorkflowStepInteraction {
148
- /** The workflow run ID */
149
- runId: string;
150
- /** The unique step ID */
151
- stepId: string;
152
- /** Current attempt number (1-indexed, increments on retry) */
153
- attemptCount: number;
154
- }
155
- /**
156
- * Workflow interaction object for middleware
157
- * Provides workflow-specific capabilities to function execution
158
- */
159
- export interface PikkuWorkflowInteraction {
160
- /** The workflow name */
161
- workflowName: string;
162
- /** The current run ID */
163
- runId: string;
164
- /** Get the current workflow run */
165
- getRun: () => Promise<WorkflowRun>;
166
- /** Execute a workflow step (overloaded - RPC or inline form) */
167
- do: WorkflowInteractionDoRPC & WorkflowInteractionDoInline;
168
- /** Sleep for a duration */
169
- sleep: WorkflowInteractionSleep;
170
- /** Cancel the current workflow run */
171
- cancel: (reason?: string) => Promise<void>;
172
- }
173
175
  /**
174
176
  * Workflow client interface
175
177
  */
@@ -184,51 +186,56 @@ export interface PikkuWorkflow {
184
186
  cancelRun: (runId: string) => Promise<void>;
185
187
  }
186
188
  /**
187
- * Workflows metadata for inspector/CLI
189
+ * Context variable definition (serialized from Zod schema or type inference)
188
190
  */
189
- export type WorkflowsMeta = Record<string, {
190
- pikkuFuncName: string;
191
- workflowName: string;
191
+ export interface ContextVariable {
192
+ /** Variable type */
193
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array';
194
+ /** Default value */
195
+ default?: unknown;
196
+ /** Description for UI/docs */
192
197
  description?: string;
193
- session?: undefined;
194
- docs?: PikkuDocs;
195
- tags?: string[];
196
- middleware?: MiddlewareMetadata[];
198
+ }
199
+ /**
200
+ * Workflow context - state variables with defaults and types
201
+ */
202
+ export type WorkflowContext = Record<string, ContextVariable>;
203
+ /**
204
+ * Workflows metadata for inspector/CLI (DSL step-based format)
205
+ */
206
+ export type WorkflowsMeta = Record<string, CommonWireMeta & {
207
+ workflowName: string;
197
208
  steps: WorkflowStepMeta[];
209
+ context?: WorkflowContext;
210
+ dsl?: boolean;
198
211
  }>;
199
212
  /**
200
- * Interface for workflow orchestration
201
- * Handles workflow execution, replay, orchestration logic, and run-level state
202
- */
203
- export interface WorkflowService {
204
- createRun(workflowName: string, input: any): Promise<string>;
205
- getRun(id: string): Promise<WorkflowRun | null>;
206
- getRunHistory(runId: string): Promise<Array<StepState & {
207
- stepName: string;
208
- }>>;
209
- updateRunStatus(id: string, status: WorkflowStatus, output?: any, error?: SerializedError): Promise<void>;
210
- withRunLock<T>(id: string, fn: () => Promise<T>): Promise<T>;
211
- close(): Promise<void>;
212
- resumeWorkflow(runId: string): Promise<void>;
213
- setServices(singletonServices: CoreSingletonServices, createSessionServices: CreateSessionServices, config: CoreConfig): void;
214
- startWorkflow<I>(name: string, input: I, rpcService: any): Promise<{
215
- runId: string;
216
- }>;
217
- runWorkflowJob(runId: string, rpcService: any): Promise<void>;
218
- orchestrateWorkflow(runId: string, rpcService: any): Promise<void>;
219
- executeWorkflowSleep(runId: string, stepId: string): Promise<void>;
220
- insertStepState(runId: string, stepName: string, rpcName: string, data: any, stepOptions?: {
221
- retries?: number;
222
- retryDelay?: string | number;
223
- }): Promise<StepState>;
224
- getStepState(runId: string, stepName: string): Promise<StepState>;
225
- setStepRunning(stepId: string): Promise<void>;
226
- setStepScheduled(stepId: string): Promise<void>;
227
- setStepResult(stepId: string, result: any): Promise<void>;
228
- setStepError(stepId: string, error: Error): Promise<void>;
229
- createRetryAttempt(stepId: string, status: 'pending' | 'running'): Promise<StepState>;
230
- executeWorkflowStep(runId: string, stepName: string, rpcName: string | null, data: any, rpcService: any): Promise<void>;
213
+ * Unified workflow runtime meta (used by runtime to execute workflows)
214
+ * This is the format stored in pikkuState('workflows', 'meta')
215
+ * Both DSL and graph-based workflows are converted to this format
216
+ */
217
+ export interface WorkflowRuntimeMeta {
218
+ /** Workflow name (used as key in registrations) */
219
+ name: string;
220
+ /** Pikku function name (for execution) */
221
+ pikkuFuncName: string;
222
+ /** Source type: 'dsl' (serializable), 'complex' (has inline steps), 'graph' */
223
+ source?: 'dsl' | 'complex' | 'graph';
224
+ /** Optional description */
225
+ description?: string;
226
+ /** Tags for organization */
227
+ tags?: string[];
228
+ /** Wires - how the workflow is triggered */
229
+ wires?: WorkflowWires;
230
+ /** Serialized nodes */
231
+ nodes?: Record<string, any>;
232
+ /** Entry node IDs for graph workflows (computed at build time) */
233
+ entryNodeIds?: string[];
231
234
  }
235
+ /**
236
+ * Unified workflow runtime metadata map
237
+ */
238
+ export type WorkflowsRuntimeMeta = Record<string, WorkflowRuntimeMeta>;
232
239
  /**
233
240
  * Worker input types for generated queue workers
234
241
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",
@@ -30,6 +30,7 @@
30
30
  "./mcp": "./dist/wirings/mcp/index.js",
31
31
  "./cli": "./dist/wirings/cli/index.js",
32
32
  "./cli/channel": "./dist/wirings/cli/channel/index.js",
33
+ "./forge-node": "./dist/wirings/forge-node/index.js",
33
34
  "./errors": "./dist/errors/index.js",
34
35
  "./services": "./dist/services/index.js",
35
36
  "./services/local-content": "./dist/services/local-content.js",
@@ -42,10 +43,18 @@
42
43
  "picoquery": "^2.5.0"
43
44
  },
44
45
  "devDependencies": {
45
- "@types/node": "^24.9.1",
46
+ "@types/node": "^24.10.1",
46
47
  "tsx": "^4.20.6",
47
48
  "typescript": "^5.9"
48
49
  },
50
+ "peerDependencies": {
51
+ "zod": "^4.0.0"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "zod": {
55
+ "optional": true
56
+ }
57
+ },
49
58
  "engines": {
50
59
  "node": ">=18"
51
60
  }
@@ -30,7 +30,7 @@ export interface ErrorDetails {
30
30
  * @param details - The details of the error.
31
31
  */
32
32
  export const addError = (error: any, { status, message }: ErrorDetails) => {
33
- pikkuState('misc', 'errors').set(error, { status, message })
33
+ pikkuState(null, 'misc', 'errors').set(error, { status, message })
34
34
  }
35
35
 
36
36
  /**
@@ -53,10 +53,10 @@ export const addErrors = (
53
53
  export const getErrorResponse = (
54
54
  error: Error
55
55
  ): { status: number; message: string; mcpCode?: number } | undefined => {
56
- const errors = Array.from(pikkuState('misc', 'errors').entries())
56
+ const errors = Array.from(pikkuState(null, 'misc', 'errors').entries())
57
57
  const foundError = errors.find(([e]) => e.name === error.constructor.name)
58
58
  if (foundError) {
59
59
  return foundError[1]
60
60
  }
61
- return pikkuState('misc', 'errors').get(error)
61
+ return pikkuState(null, 'misc', 'errors').get(error)
62
62
  }
@@ -3,10 +3,10 @@
3
3
  */
4
4
  import { addError, PikkuError } from './error-handler.js'
5
5
 
6
- export class InvalidMiddlewareInteractionError extends PikkuError {}
7
- addError(InvalidMiddlewareInteractionError, {
6
+ export class InvalidMiddlewareWireError extends PikkuError {}
7
+ addError(InvalidMiddlewareWireError, {
8
8
  status: 500,
9
- message: 'The middleware interaction is invalid for the current wiring type.',
9
+ message: 'The middleware wire is invalid for the current wiring type.',
10
10
  })
11
11
 
12
12
  /**
@@ -7,44 +7,22 @@ import {
7
7
  pikkuMiddlewareFactory,
8
8
  } from './index.js'
9
9
 
10
- test('pikkuPermission factory function', async () => {
11
- const permission = pikkuPermission(async ({ logger }, data, session) => {
12
- return true
13
- })
14
-
15
- assert.strictEqual(typeof permission, 'function')
16
- assert.strictEqual(permission.length, 3) // services, data, session
17
- })
18
-
19
- test('pikkuMiddleware factory function', async () => {
20
- const middleware = pikkuMiddleware(async ({ logger }, interactions, next) => {
21
- await next()
22
- })
23
-
24
- assert.strictEqual(typeof middleware, 'function')
25
- assert.strictEqual(middleware.length, 3) // services, interactions, next
26
- })
27
-
28
10
  test('pikkuPermission returns the same function', async () => {
29
- const originalFn = async ({ logger }, data, session) => true
11
+ const originalFn = async () => true
30
12
  const wrappedFn = pikkuPermission(originalFn)
31
-
32
13
  assert.strictEqual(wrappedFn, originalFn)
33
14
  })
34
15
 
35
16
  test('pikkuMiddleware returns the same function', async () => {
36
- const originalFn = async ({ logger }, interactions, next) => {
37
- await next()
38
- }
17
+ const originalFn = async ({ logger }, wires, next) => next
39
18
  const wrappedFn = pikkuMiddleware(originalFn)
40
-
41
19
  assert.strictEqual(wrappedFn, originalFn)
42
20
  })
43
21
 
44
22
  test('pikkuPermissionFactory creates a factory function', async () => {
45
23
  const factory = pikkuPermissionFactory<{ role: string }>(({ role }) => {
46
- return pikkuPermission(async ({ logger }, data, session) => {
47
- return session?.role === role
24
+ return pikkuPermission(async ({ logger }, data, { initialSession }) => {
25
+ return (initialSession as any)?.role === role
48
26
  })
49
27
  })
50
28
 
@@ -59,7 +37,7 @@ test('pikkuPermissionFactory creates a factory function', async () => {
59
37
 
60
38
  test('pikkuMiddlewareFactory creates a factory function', async () => {
61
39
  const factory = pikkuMiddlewareFactory<{ message: string }>(({ message }) => {
62
- return pikkuMiddleware(async ({ logger }, interactions, next) => {
40
+ return pikkuMiddleware(async ({ logger }, wires, next) => {
63
41
  logger.info(message)
64
42
  await next()
65
43
  })
@@ -71,26 +49,21 @@ test('pikkuMiddlewareFactory creates a factory function', async () => {
71
49
  // Call the factory to get middleware
72
50
  const middleware = factory({ message: 'test' })
73
51
  assert.strictEqual(typeof middleware, 'function')
74
- assert.strictEqual(middleware.length, 3) // services, interactions, next
52
+ assert.strictEqual(middleware.length, 3) // services, wires, next
75
53
  })
76
54
 
77
55
  test('pikkuPermissionFactory returns the same factory', async () => {
78
- const originalFactory = ({ role }) =>
79
- pikkuPermission(async ({ logger }, data, session) => {
80
- return session?.role === role
81
- })
82
- const wrappedFactory = pikkuPermissionFactory(originalFactory)
83
-
56
+ const originalFactory = () => pikkuPermission(async () => true)
57
+ const wrappedFactory = pikkuPermissionFactory(originalFactory as any)
84
58
  assert.strictEqual(wrappedFactory, originalFactory)
85
59
  })
86
60
 
87
61
  test('pikkuMiddlewareFactory returns the same factory', async () => {
88
62
  const originalFactory = ({ message }) =>
89
- pikkuMiddleware(async ({ logger }, interactions, next) => {
63
+ pikkuMiddleware(async ({ logger }, _wires, next) => {
90
64
  logger.info(message)
91
65
  await next()
92
66
  })
93
67
  const wrappedFactory = pikkuMiddlewareFactory(originalFactory)
94
-
95
68
  assert.strictEqual(wrappedFactory, originalFactory)
96
69
  })