@pikku/core 0.11.1 → 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 (143) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/errors/error-handler.js +3 -3
  3. package/dist/function/function-runner.d.ts +4 -3
  4. package/dist/function/function-runner.js +60 -14
  5. package/dist/function/functions.types.d.ts +84 -5
  6. package/dist/function/functions.types.js +41 -1
  7. package/dist/index.d.ts +6 -2
  8. package/dist/index.js +5 -2
  9. package/dist/middleware/auth-apikey.d.ts +1 -1
  10. package/dist/middleware/auth-bearer.d.ts +1 -1
  11. package/dist/middleware/auth-cookie.d.ts +1 -1
  12. package/dist/middleware/timeout.d.ts +1 -1
  13. package/dist/middleware-runner.d.ts +3 -14
  14. package/dist/middleware-runner.js +8 -8
  15. package/dist/permissions.d.ts +3 -86
  16. package/dist/permissions.js +11 -67
  17. package/dist/pikku-state.d.ts +32 -104
  18. package/dist/pikku-state.js +140 -66
  19. package/dist/schema.d.ts +8 -6
  20. package/dist/schema.js +25 -13
  21. package/dist/services/workflow-service.d.ts +38 -0
  22. package/dist/services/workflow-service.js +1 -0
  23. package/dist/types/core.types.d.ts +12 -4
  24. package/dist/types/core.types.js +1 -1
  25. package/dist/types/state.types.d.ts +135 -0
  26. package/dist/types/state.types.js +1 -0
  27. package/dist/utils.d.ts +8 -0
  28. package/dist/utils.js +45 -0
  29. package/dist/wirings/channel/channel-handler.js +1 -1
  30. package/dist/wirings/channel/channel-runner.js +5 -5
  31. package/dist/wirings/channel/log-channels.js +1 -1
  32. package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -2
  33. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
  34. package/dist/wirings/cli/cli-runner.js +10 -10
  35. package/dist/wirings/cli/cli.types.d.ts +1 -0
  36. package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
  37. package/dist/wirings/forge-node/forge-node.types.js +38 -0
  38. package/dist/wirings/forge-node/index.d.ts +1 -0
  39. package/dist/wirings/forge-node/index.js +1 -0
  40. package/dist/wirings/http/http-runner.d.ts +2 -2
  41. package/dist/wirings/http/http-runner.js +21 -12
  42. package/dist/wirings/http/http.types.d.ts +14 -1
  43. package/dist/wirings/http/log-http-routes.js +1 -1
  44. package/dist/wirings/http/routers/path-to-regex.js +2 -2
  45. package/dist/wirings/mcp/mcp-runner.js +21 -21
  46. package/dist/wirings/queue/queue-runner.js +6 -6
  47. package/dist/wirings/rpc/index.d.ts +1 -1
  48. package/dist/wirings/rpc/index.js +1 -1
  49. package/dist/wirings/rpc/rpc-runner.d.ts +7 -8
  50. package/dist/wirings/rpc/rpc-runner.js +62 -14
  51. package/dist/wirings/rpc/rpc-types.d.ts +7 -0
  52. package/dist/wirings/scheduler/log-schedulers.js +1 -1
  53. package/dist/wirings/scheduler/scheduler-runner.js +5 -5
  54. package/dist/wirings/trigger/index.d.ts +2 -0
  55. package/dist/wirings/trigger/index.js +2 -0
  56. package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
  57. package/dist/wirings/trigger/trigger-runner.js +57 -0
  58. package/dist/wirings/trigger/trigger.types.d.ts +42 -0
  59. package/dist/wirings/trigger/trigger.types.js +1 -0
  60. package/dist/wirings/workflow/dsl/index.d.ts +5 -0
  61. package/dist/wirings/workflow/dsl/index.js +4 -0
  62. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
  63. package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
  64. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
  65. package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
  66. package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
  67. package/dist/wirings/workflow/graph/graph-node.js +58 -0
  68. package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
  69. package/dist/wirings/workflow/graph/graph-runner.js +452 -0
  70. package/dist/wirings/workflow/graph/index.d.ts +3 -0
  71. package/dist/wirings/workflow/graph/index.js +3 -0
  72. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
  73. package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
  74. package/dist/wirings/workflow/index.d.ts +7 -12
  75. package/dist/wirings/workflow/index.js +6 -11
  76. package/dist/wirings/workflow/pikku-workflow-service.d.ts +96 -6
  77. package/dist/wirings/workflow/pikku-workflow-service.js +230 -103
  78. package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
  79. package/dist/wirings/workflow/wire-workflow.js +53 -0
  80. package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
  81. package/dist/wirings/workflow/workflow-utils.js +66 -0
  82. package/dist/wirings/workflow/workflow.types.d.ts +133 -211
  83. package/package.json +10 -1
  84. package/src/errors/error-handler.ts +3 -3
  85. package/src/function/function-runner.test.ts +1 -1
  86. package/src/function/function-runner.ts +86 -16
  87. package/src/function/functions.types.ts +126 -4
  88. package/src/index.ts +10 -5
  89. package/src/middleware-runner.ts +16 -9
  90. package/src/permissions.test.ts +28 -86
  91. package/src/permissions.ts +21 -80
  92. package/src/pikku-state.ts +156 -201
  93. package/src/schema.ts +42 -13
  94. package/src/services/workflow-service.ts +74 -0
  95. package/src/types/core.types.ts +12 -3
  96. package/src/types/state.types.ts +195 -0
  97. package/src/utils.ts +55 -0
  98. package/src/wirings/channel/channel-handler.ts +1 -1
  99. package/src/wirings/channel/channel-runner.ts +5 -5
  100. package/src/wirings/channel/local/local-channel-runner.test.ts +3 -1
  101. package/src/wirings/channel/log-channels.ts +1 -1
  102. package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -2
  103. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
  104. package/src/wirings/cli/cli-runner.test.ts +19 -19
  105. package/src/wirings/cli/cli-runner.ts +10 -9
  106. package/src/wirings/cli/cli.types.ts +1 -0
  107. package/src/wirings/forge-node/forge-node.types.ts +135 -0
  108. package/src/wirings/forge-node/index.ts +1 -0
  109. package/src/wirings/http/http-runner.test.ts +2 -2
  110. package/src/wirings/http/http-runner.ts +30 -13
  111. package/src/wirings/http/http.types.ts +14 -0
  112. package/src/wirings/http/log-http-routes.ts +1 -1
  113. package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
  114. package/src/wirings/http/routers/path-to-regex.ts +2 -2
  115. package/src/wirings/mcp/mcp-runner.ts +21 -21
  116. package/src/wirings/queue/queue-runner.test.ts +19 -19
  117. package/src/wirings/queue/queue-runner.ts +6 -6
  118. package/src/wirings/rpc/index.ts +1 -1
  119. package/src/wirings/rpc/rpc-runner.ts +88 -22
  120. package/src/wirings/rpc/rpc-types.ts +8 -0
  121. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  122. package/src/wirings/scheduler/scheduler-runner.test.ts +27 -27
  123. package/src/wirings/scheduler/scheduler-runner.ts +5 -5
  124. package/src/wirings/trigger/index.ts +2 -0
  125. package/src/wirings/trigger/trigger-runner.ts +96 -0
  126. package/src/wirings/trigger/trigger.types.ts +56 -0
  127. package/src/wirings/workflow/dsl/index.ts +30 -0
  128. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
  129. package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
  130. package/src/wirings/workflow/graph/graph-node.ts +227 -0
  131. package/src/wirings/workflow/graph/graph-runner.ts +694 -0
  132. package/src/wirings/workflow/graph/index.ts +3 -0
  133. package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
  134. package/src/wirings/workflow/index.ts +53 -26
  135. package/src/wirings/workflow/pikku-workflow-service.ts +333 -117
  136. package/src/wirings/workflow/wire-workflow.ts +94 -0
  137. package/src/wirings/workflow/workflow-utils.ts +120 -0
  138. package/src/wirings/workflow/workflow.types.ts +166 -277
  139. package/tsconfig.tsbuildinfo +1 -1
  140. package/dist/wirings/workflow/workflow-runner.d.ts +0 -34
  141. package/dist/wirings/workflow/workflow-runner.js +0 -65
  142. package/src/function/function-runner.ts.bak +0 -188
  143. package/src/wirings/workflow/workflow-runner.ts +0 -72
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  ## 0.11.0
2
2
 
3
+ ## 0.11.2
4
+
5
+ ### Patch Changes
6
+
7
+ - db9c7bf: Add workflow graph system with type-safe builder
8
+
9
+ ## 0.11.2
10
+
11
+ ### Features
12
+
13
+ - f35e89da: Add workflow graph system with type-safe builder
14
+ - `createGraph<RPCMap>()` for building workflow graphs with full type safety
15
+ - `wireWorkflowGraph()` for registering workflow graphs
16
+ - `graphNode()` helper for type-safe node creation
17
+ - Graph scheduler for execution (continueGraph, startWorkflowGraph)
18
+ - TypedRef for type-safe input refs in workflow graphs
19
+ - `setBranchTaken` added to WorkflowService interface
20
+ - Trigger runner for workflow triggers
21
+
22
+ ### Breaking Changes
23
+
24
+ - Rename `pikkuWorkflowFunc` to `pikkuWorkflowComplexFunc`
25
+ - Rename `pikkuWorkflowDSTFunc` to `pikkuWorkflowFunc`
26
+
3
27
  ## 0.11.1
4
28
 
5
29
  ### Patch Changes
@@ -19,7 +19,7 @@ export class PikkuError extends Error {
19
19
  * @param details - The details of the error.
20
20
  */
21
21
  export const addError = (error, { status, message }) => {
22
- pikkuState('misc', 'errors').set(error, { status, message });
22
+ pikkuState(null, 'misc', 'errors').set(error, { status, message });
23
23
  };
24
24
  /**
25
25
  * Adds multiple errors to the API errors map.
@@ -36,10 +36,10 @@ export const addErrors = (errors) => {
36
36
  * @returns An object containing the status and message, or undefined if the error is not found.
37
37
  */
38
38
  export const getErrorResponse = (error) => {
39
- const errors = Array.from(pikkuState('misc', 'errors').entries());
39
+ const errors = Array.from(pikkuState(null, 'misc', 'errors').entries());
40
40
  const foundError = errors.find(([e]) => e.name === error.constructor.name);
41
41
  if (foundError) {
42
42
  return foundError[1];
43
43
  }
44
- return pikkuState('misc', 'errors').get(error);
44
+ return pikkuState(null, 'misc', 'errors').get(error);
45
45
  };
@@ -1,9 +1,9 @@
1
1
  import { CoreServices, CoreUserSession, CorePikkuMiddleware, PikkuWiringTypes, PikkuWire, MiddlewareMetadata, PermissionMetadata, CoreSingletonServices, CreateWireServices } from '../types/core.types.js';
2
2
  import { CorePermissionGroup, CorePikkuFunctionConfig, CorePikkuPermission } from './functions.types.js';
3
3
  import { SessionService } from '../services/user-session-service.js';
4
- export declare const addFunction: (funcName: string, funcConfig: CorePikkuFunctionConfig<any, any>) => void;
5
- export declare const runPikkuFuncDirectly: <In, Out>(funcName: string, allServices: CoreServices, wire: PikkuWire, data: In, userSession?: SessionService<CoreUserSession>) => Promise<Out>;
6
- export declare const runPikkuFunc: <In = any, Out = any>(wireType: PikkuWiringTypes, wireId: string, funcName: string, { singletonServices, createWireServices, data, auth: wiringAuth, inheritedMiddleware, wireMiddleware, inheritedPermissions, wirePermissions, coerceDataFromSchema, tags, wire, }: {
4
+ export declare const addFunction: (funcName: string, funcConfig: CorePikkuFunctionConfig<any, any>, packageName?: string | null) => void;
5
+ export declare const runPikkuFuncDirectly: <In, Out>(funcName: string, allServices: CoreServices, wire: PikkuWire, data: In, userSession?: SessionService<CoreUserSession>, packageName?: string | null) => Promise<Out>;
6
+ export declare const runPikkuFunc: <In = any, Out = any>(wireType: PikkuWiringTypes, wireId: string, funcName: string, { singletonServices, createWireServices, data, auth: wiringAuth, inheritedMiddleware, wireMiddleware, inheritedPermissions, wirePermissions, coerceDataFromSchema, tags, wire, packageName, }: {
7
7
  singletonServices: CoreSingletonServices;
8
8
  createWireServices?: CreateWireServices;
9
9
  data: () => Promise<In> | In;
@@ -15,4 +15,5 @@ export declare const runPikkuFunc: <In = any, Out = any>(wireType: PikkuWiringTy
15
15
  coerceDataFromSchema?: boolean;
16
16
  tags?: string[];
17
17
  wire: PikkuWire;
18
+ packageName?: string | null;
18
19
  }) => Promise<Out>;
@@ -5,11 +5,42 @@ import { coerceTopLevelDataFromSchema, validateSchema } from '../schema.js';
5
5
  import { ForbiddenError } from '../errors/errors.js';
6
6
  import { rpcService } from '../wirings/rpc/rpc-runner.js';
7
7
  import { closeWireServices } from '../utils.js';
8
- export const addFunction = (funcName, funcConfig) => {
9
- pikkuState('function', 'functions').set(funcName, funcConfig);
8
+ /**
9
+ * Get or create singleton services for an external package.
10
+ * Services are cached in pikkuState to avoid recreation on each call.
11
+ *
12
+ * @param packageName - The external package name
13
+ * @param parentServices - The parent/caller's singleton services (used as base)
14
+ * @returns The package's singleton services
15
+ */
16
+ const getOrCreatePackageSingletonServices = async (packageName, parentServices) => {
17
+ // Check if we already have cached singleton services for this package
18
+ const cachedServices = pikkuState(packageName, 'package', 'singletonServices');
19
+ if (cachedServices) {
20
+ return cachedServices;
21
+ }
22
+ // Get the package's service factories
23
+ const factories = pikkuState(packageName, 'package', 'factories');
24
+ if (!factories || !factories.createSingletonServices) {
25
+ // No factories registered, use parent services
26
+ return parentServices;
27
+ }
28
+ // Create config for the package (use parent config if no factory)
29
+ let config = parentServices.config;
30
+ if (factories.createConfig) {
31
+ config = await factories.createConfig(parentServices.variables);
32
+ }
33
+ // Create singleton services for the package, passing parent services as existing
34
+ const packageServices = await factories.createSingletonServices(config, parentServices);
35
+ // Cache the services
36
+ pikkuState(packageName, 'package', 'singletonServices', packageServices);
37
+ return packageServices;
10
38
  };
11
- export const runPikkuFuncDirectly = async (funcName, allServices, wire, data, userSession) => {
12
- const funcConfig = pikkuState('function', 'functions').get(funcName);
39
+ export const addFunction = (funcName, funcConfig, packageName = null) => {
40
+ pikkuState(packageName, 'function', 'functions').set(funcName, funcConfig);
41
+ };
42
+ export const runPikkuFuncDirectly = async (funcName, allServices, wire, data, userSession, packageName = null) => {
43
+ const funcConfig = pikkuState(packageName, 'function', 'functions').get(funcName);
13
44
  if (!funcConfig) {
14
45
  throw new Error(`Function not found: ${funcName}`);
15
46
  }
@@ -20,15 +51,28 @@ export const runPikkuFuncDirectly = async (funcName, allServices, wire, data, us
20
51
  };
21
52
  return (await funcConfig.func(allServices, data, wireWithSession));
22
53
  };
23
- export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServices, createWireServices, data, auth: wiringAuth, inheritedMiddleware, wireMiddleware, inheritedPermissions, wirePermissions, coerceDataFromSchema, tags = [], wire, }) => {
24
- const funcConfig = pikkuState('function', 'functions').get(funcName);
54
+ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServices, createWireServices, data, auth: wiringAuth, inheritedMiddleware, wireMiddleware, inheritedPermissions, wirePermissions, coerceDataFromSchema, tags = [], wire, packageName = null, }) => {
55
+ const funcConfig = pikkuState(packageName, 'function', 'functions').get(funcName);
25
56
  if (!funcConfig) {
26
57
  throw new Error(`Function not found: ${funcName}`);
27
58
  }
28
- const funcMeta = pikkuState('function', 'meta')[funcName];
59
+ const allMeta = pikkuState(packageName, 'function', 'meta');
60
+ const funcMeta = allMeta[funcName];
29
61
  if (!funcMeta) {
30
62
  throw new Error(`Function meta not found: ${funcName}`);
31
63
  }
64
+ // For external packages, get or create their singleton services
65
+ const resolvedSingletonServices = packageName
66
+ ? await getOrCreatePackageSingletonServices(packageName, singletonServices)
67
+ : singletonServices;
68
+ // Get the package's createWireServices if available
69
+ let resolvedCreateWireServices = createWireServices;
70
+ if (packageName) {
71
+ const factories = pikkuState(packageName, 'package', 'factories');
72
+ if (factories?.createWireServices) {
73
+ resolvedCreateWireServices = factories.createWireServices;
74
+ }
75
+ }
32
76
  // Convert tags to PermissionMetadata and merge with inheritedPermissions
33
77
  const mergedInheritedPermissions = [
34
78
  ...(inheritedPermissions || []),
@@ -60,10 +104,10 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
60
104
  const inputSchemaName = funcMeta.inputSchemaName;
61
105
  if (inputSchemaName) {
62
106
  // Validate request data against the defined schema, if any
63
- await validateSchema(singletonServices.logger, singletonServices.schema, inputSchemaName, actualData);
107
+ await validateSchema(resolvedSingletonServices.logger, resolvedSingletonServices.schema, inputSchemaName, actualData, packageName);
64
108
  // Coerce (top level) query string parameters or date objects if specified by the schema
65
109
  if (coerceDataFromSchema) {
66
- coerceTopLevelDataFromSchema(inputSchemaName, actualData);
110
+ coerceTopLevelDataFromSchema(inputSchemaName, actualData, packageName);
67
111
  }
68
112
  }
69
113
  await runPermissions(wireType, wireId, {
@@ -71,13 +115,14 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
71
115
  wirePermissions: wirePermissions,
72
116
  funcInheritedPermissions: funcMeta.permissions,
73
117
  funcPermissions: funcConfig.permissions,
74
- services: singletonServices,
118
+ services: resolvedSingletonServices,
75
119
  wire: { ...wireWithInitialSession, rpc: undefined },
76
120
  data: actualData,
121
+ packageName,
77
122
  });
78
- const wireServices = await createWireServices?.(singletonServices, wireWithInitialSession);
123
+ const wireServices = await resolvedCreateWireServices?.(resolvedSingletonServices, wireWithInitialSession);
79
124
  try {
80
- const services = { ...singletonServices, ...wireServices };
125
+ const services = { ...resolvedSingletonServices, ...wireServices };
81
126
  const rpc = rpcService.getContextRPCService(services, wireWithInitialSession);
82
127
  return await funcConfig.func(services, actualData, {
83
128
  ...wireWithInitialSession,
@@ -86,7 +131,7 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
86
131
  }
87
132
  finally {
88
133
  if (wireServices) {
89
- await closeWireServices(singletonServices.logger, wireServices);
134
+ await closeWireServices(resolvedSingletonServices.logger, wireServices);
90
135
  }
91
136
  }
92
137
  };
@@ -95,9 +140,10 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
95
140
  wireMiddleware,
96
141
  funcInheritedMiddleware: funcMeta.middleware,
97
142
  funcMiddleware: funcConfig.middleware,
143
+ packageName,
98
144
  });
99
145
  if (allMiddleware.length > 0) {
100
- return (await runMiddleware(singletonServices, wire, allMiddleware, executeFunction));
146
+ return (await runMiddleware(resolvedSingletonServices, wire, allMiddleware, executeFunction));
101
147
  }
102
148
  return (await executeFunction());
103
149
  };
@@ -36,8 +36,8 @@ export type CorePikkuPermission<In = any, Services extends CoreSingletonServices
36
36
  export type CorePikkuPermissionConfig<In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PikkuWire<In, never, false, CoreUserSession> = PikkuWire<In, never, false, CoreUserSession>> = {
37
37
  /** The permission function */
38
38
  func: CorePikkuPermission<In, Services, Wire>;
39
- /** Optional human-readable name for the permission */
40
- name?: string;
39
+ /** Optional human-readable title for the permission */
40
+ title?: string;
41
41
  /** Optional description of what the permission checks */
42
42
  description?: string;
43
43
  };
@@ -57,7 +57,7 @@ export type CorePikkuPermissionConfig<In = any, Services extends CoreSingletonSe
57
57
  *
58
58
  * // Configuration object syntax with metadata
59
59
  * export const adminPermission = pikkuPermission({
60
- * name: 'Admin Permission',
60
+ * title: 'Admin Permission',
61
61
  * description: 'Checks if user has admin role',
62
62
  * func: async ({ logger }, _data, { session }) => {
63
63
  * const currentSession = await session.get()
@@ -98,8 +98,20 @@ export type CorePikkuPermissionFactory<In = any, Services extends CoreSingletonS
98
98
  */
99
99
  export declare const pikkuPermissionFactory: <In = any>(factory: CorePikkuPermissionFactory<In>) => CorePikkuPermissionFactory<In>;
100
100
  export type CorePermissionGroup<PikkuPermission = CorePikkuPermission<any>> = Record<string, PikkuPermission | PikkuPermission[]> | undefined;
101
- export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any, any, any, any> | CorePikkuFunctionSessionless<any, any, any, any>, PikkuPermission extends CorePikkuPermission<any, any, any> = CorePikkuPermission<any>, PikkuMiddleware extends CorePikkuMiddleware<any, any> = CorePikkuMiddleware<any, any>> = {
102
- name?: string;
101
+ /**
102
+ * Zod schema type - matches z.ZodType shape for type inference
103
+ * This avoids requiring zod as a dependency while allowing schema inference
104
+ */
105
+ export type ZodLike<T = any> = {
106
+ _input: T;
107
+ _output: T;
108
+ };
109
+ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any, any, any, any> | CorePikkuFunctionSessionless<any, any, any, any>, PikkuPermission extends CorePikkuPermission<any, any, any> = CorePikkuPermission<any>, PikkuMiddleware extends CorePikkuMiddleware<any, any> = CorePikkuMiddleware<any, any>, InputSchema extends ZodLike | undefined = undefined, OutputSchema extends ZodLike | undefined = undefined> = {
110
+ /** Optional human-readable title for the function */
111
+ title?: string;
112
+ /** Optional description of what the function does */
113
+ description?: string;
114
+ override?: string;
103
115
  tags?: string[];
104
116
  expose?: boolean;
105
117
  internal?: boolean;
@@ -107,4 +119,71 @@ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any,
107
119
  auth?: boolean;
108
120
  permissions?: CorePermissionGroup<PikkuPermission>;
109
121
  middleware?: PikkuMiddleware[];
122
+ input?: InputSchema;
123
+ output?: OutputSchema;
110
124
  };
125
+ /**
126
+ * A trigger function that sets up a subscription and returns a teardown function.
127
+ * The trigger is fired via wire.trigger.trigger(data).
128
+ *
129
+ * @template TConfig - Configuration type (hardcoded when wired)
130
+ * @template TOutput - Output type produced when trigger fires
131
+ * @template Services - Services available to the trigger
132
+ */
133
+ export type CorePikkuTriggerFunction<TConfig = unknown, TOutput = unknown, Services extends CoreSingletonServices = CoreSingletonServices> = (services: Services, config: TConfig, wire: {
134
+ trigger: {
135
+ trigger: (data: TOutput) => void;
136
+ };
137
+ }) => Promise<() => void | Promise<void>>;
138
+ /**
139
+ * Configuration object for creating a trigger function with metadata
140
+ */
141
+ export type CorePikkuTriggerFunctionConfig<TConfig = unknown, TOutput = unknown, Services extends CoreSingletonServices = CoreSingletonServices, ConfigSchema extends ZodLike | undefined = undefined, OutputSchema extends ZodLike | undefined = undefined> = {
142
+ /** Optional human-readable title for the trigger */
143
+ title?: string;
144
+ /** Optional description of what the trigger does */
145
+ description?: string;
146
+ /** Optional tags for categorization */
147
+ tags?: string[];
148
+ /** The trigger function */
149
+ func: CorePikkuTriggerFunction<TConfig, TOutput, Services>;
150
+ /** Optional Zod schema for config validation */
151
+ config?: ConfigSchema;
152
+ /** Optional Zod schema for output validation */
153
+ output?: OutputSchema;
154
+ };
155
+ /**
156
+ * Factory function for creating trigger functions
157
+ * Supports both direct function and configuration object syntax
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * // Direct function syntax
162
+ * export const redisSubscribeTrigger = pikkuTriggerFunc<
163
+ * { channel: string },
164
+ * { message: string }
165
+ * >(async ({ redis }, { channel }, { trigger }) => {
166
+ * const subscriber = redis.duplicate()
167
+ * await subscriber.subscribe(channel, (msg) => {
168
+ * trigger.trigger({ message: msg })
169
+ * })
170
+ * return () => subscriber.unsubscribe()
171
+ * })
172
+ *
173
+ * // Configuration object syntax with metadata
174
+ * export const redisSubscribeTrigger = pikkuTriggerFunc({
175
+ * title: 'Redis Subscribe Trigger',
176
+ * description: 'Listens to Redis pub/sub channel',
177
+ * config: z.object({ channel: z.string() }),
178
+ * output: z.object({ message: z.string() }),
179
+ * func: async ({ redis }, { channel }, { trigger }) => {
180
+ * const subscriber = redis.duplicate()
181
+ * await subscriber.subscribe(channel, (msg) => {
182
+ * trigger.trigger({ message: msg })
183
+ * })
184
+ * return () => subscriber.unsubscribe()
185
+ * }
186
+ * })
187
+ * ```
188
+ */
189
+ export declare const pikkuTriggerFunc: <TConfig = unknown, TOutput = unknown, Services extends CoreSingletonServices = CoreSingletonServices, ConfigSchema extends ZodLike | undefined = undefined, OutputSchema extends ZodLike | undefined = undefined>(triggerOrConfig: CorePikkuTriggerFunction<TConfig, TOutput, Services> | CorePikkuTriggerFunctionConfig<TConfig, TOutput, Services, ConfigSchema, OutputSchema>) => CorePikkuTriggerFunctionConfig<TConfig, TOutput, Services, ConfigSchema, OutputSchema>;
@@ -14,7 +14,7 @@
14
14
  *
15
15
  * // Configuration object syntax with metadata
16
16
  * export const adminPermission = pikkuPermission({
17
- * name: 'Admin Permission',
17
+ * title: 'Admin Permission',
18
18
  * description: 'Checks if user has admin role',
19
19
  * func: async ({ logger }, _data, { session }) => {
20
20
  * const currentSession = await session.get()
@@ -49,3 +49,43 @@ export const pikkuPermission = (permission) => {
49
49
  export const pikkuPermissionFactory = (factory) => {
50
50
  return factory;
51
51
  };
52
+ /**
53
+ * Factory function for creating trigger functions
54
+ * Supports both direct function and configuration object syntax
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * // Direct function syntax
59
+ * export const redisSubscribeTrigger = pikkuTriggerFunc<
60
+ * { channel: string },
61
+ * { message: string }
62
+ * >(async ({ redis }, { channel }, { trigger }) => {
63
+ * const subscriber = redis.duplicate()
64
+ * await subscriber.subscribe(channel, (msg) => {
65
+ * trigger.trigger({ message: msg })
66
+ * })
67
+ * return () => subscriber.unsubscribe()
68
+ * })
69
+ *
70
+ * // Configuration object syntax with metadata
71
+ * export const redisSubscribeTrigger = pikkuTriggerFunc({
72
+ * title: 'Redis Subscribe Trigger',
73
+ * description: 'Listens to Redis pub/sub channel',
74
+ * config: z.object({ channel: z.string() }),
75
+ * output: z.object({ message: z.string() }),
76
+ * func: async ({ redis }, { channel }, { trigger }) => {
77
+ * const subscriber = redis.duplicate()
78
+ * await subscriber.subscribe(channel, (msg) => {
79
+ * trigger.trigger({ message: msg })
80
+ * })
81
+ * return () => subscriber.unsubscribe()
82
+ * }
83
+ * })
84
+ * ```
85
+ */
86
+ export const pikkuTriggerFunc = (triggerOrConfig) => {
87
+ if (typeof triggerOrConfig === 'function') {
88
+ return { func: triggerOrConfig };
89
+ }
90
+ return triggerOrConfig;
91
+ };
package/dist/index.d.ts CHANGED
@@ -17,12 +17,16 @@ export * from './wirings/scheduler/index.js';
17
17
  export * from './wirings/rpc/index.js';
18
18
  export * from './wirings/queue/index.js';
19
19
  export * from './wirings/workflow/index.js';
20
+ export * from './wirings/workflow/graph/index.js';
20
21
  export * from './wirings/mcp/index.js';
21
22
  export * from './wirings/cli/index.js';
23
+ export * from './wirings/forge-node/index.js';
24
+ export * from './wirings/trigger/index.js';
22
25
  export * from './errors/index.js';
23
26
  export * from './middleware/index.js';
24
27
  export * from './utils.js';
25
28
  export * from './time-utils.js';
26
- export { pikkuState } from './pikku-state.js';
27
- export { runMiddleware, addMiddleware, getMiddlewareByName, } from './middleware-runner.js';
29
+ export { pikkuState, initializePikkuState, resetPikkuState, addPackageServiceFactories, } from './pikku-state.js';
30
+ export type { PikkuPackageState } from './types/state.types.js';
31
+ export { runMiddleware, addMiddleware } from './middleware-runner.js';
28
32
  export { addPermission } from './permissions.js';
package/dist/index.js CHANGED
@@ -17,12 +17,15 @@ export * from './wirings/scheduler/index.js';
17
17
  export * from './wirings/rpc/index.js';
18
18
  export * from './wirings/queue/index.js';
19
19
  export * from './wirings/workflow/index.js';
20
+ export * from './wirings/workflow/graph/index.js';
20
21
  export * from './wirings/mcp/index.js';
21
22
  export * from './wirings/cli/index.js';
23
+ export * from './wirings/forge-node/index.js';
24
+ export * from './wirings/trigger/index.js';
22
25
  export * from './errors/index.js';
23
26
  export * from './middleware/index.js';
24
27
  export * from './utils.js';
25
28
  export * from './time-utils.js';
26
- export { pikkuState } from './pikku-state.js';
27
- export { runMiddleware, addMiddleware, getMiddlewareByName, } from './middleware-runner.js';
29
+ export { pikkuState, initializePikkuState, resetPikkuState, addPackageServiceFactories, } from './pikku-state.js';
30
+ export { runMiddleware, addMiddleware } from './middleware-runner.js';
28
31
  export { addPermission } from './permissions.js';
@@ -20,5 +20,5 @@ export declare const authAPIKey: import("../types/core.types.js").CorePikkuMiddl
20
20
  }, import("../types/core.types.js").CoreSingletonServices<{
21
21
  logLevel?: import("../index.js").LogLevel;
22
22
  secrets?: {};
23
- workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
23
+ workflow?: import("../index.js").WorkflowServiceConfig;
24
24
  }>, import("../types/core.types.js").CoreUserSession>;
@@ -36,5 +36,5 @@ export declare const authBearer: import("../types/core.types.js").CorePikkuMiddl
36
36
  }, import("../types/core.types.js").CoreSingletonServices<{
37
37
  logLevel?: import("../index.js").LogLevel;
38
38
  secrets?: {};
39
- workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
39
+ workflow?: import("../index.js").WorkflowServiceConfig;
40
40
  }>, CoreUserSession>;
@@ -35,5 +35,5 @@ export declare const authCookie: import("../types/core.types.js").CorePikkuMiddl
35
35
  }, import("../types/core.types.js").CoreSingletonServices<{
36
36
  logLevel?: import("../index.js").LogLevel;
37
37
  secrets?: {};
38
- workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
38
+ workflow?: import("../index.js").WorkflowServiceConfig;
39
39
  }>, import("../types/core.types.js").CoreUserSession>;
@@ -3,5 +3,5 @@ export declare const timeout: () => import("../types/core.types.js").CorePikkuMi
3
3
  }, import("../types/core.types.js").CoreSingletonServices<{
4
4
  logLevel?: import("../index.js").LogLevel;
5
5
  secrets?: {};
6
- workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
6
+ workflow?: import("../index.js").WorkflowServiceConfig;
7
7
  }>, import("../types/core.types.js").CoreUserSession>;
@@ -50,19 +50,7 @@ export declare const runMiddleware: <Middleware extends CorePikkuMiddleware>(ser
50
50
  * ])
51
51
  * ```
52
52
  */
53
- export declare const addMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(tag: string, middleware: CorePikkuMiddlewareGroup) => CorePikkuMiddlewareGroup;
54
- /**
55
- * Retrieves a registered middleware function by its name.
56
- *
57
- * This function looks up middleware that was registered with registerMiddleware.
58
- * It's used internally by the framework to resolve middleware references in metadata.
59
- *
60
- * @param {string} name - The unique name (pikkuFuncName) of the middleware function.
61
- * @returns {CorePikkuMiddleware | undefined} The middleware function, or undefined if not found.
62
- *
63
- * @internal
64
- */
65
- export declare const getMiddlewareByName: (name: string) => CorePikkuMiddleware | undefined;
53
+ export declare const addMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(tag: string, middleware: CorePikkuMiddlewareGroup, packageName?: string | null) => CorePikkuMiddlewareGroup;
66
54
  /**
67
55
  * Combines wiring-specific middleware with function-level middleware.
68
56
  *
@@ -85,9 +73,10 @@ export declare const getMiddlewareByName: (name: string) => CorePikkuMiddleware
85
73
  * })
86
74
  * ```
87
75
  */
88
- export declare const combineMiddleware: (wireType: PikkuWiringTypes, uid: string, { wireInheritedMiddleware, wireMiddleware, funcInheritedMiddleware, funcMiddleware, }?: {
76
+ export declare const combineMiddleware: (wireType: PikkuWiringTypes, uid: string, { wireInheritedMiddleware, wireMiddleware, funcInheritedMiddleware, funcMiddleware, packageName, }?: {
89
77
  wireInheritedMiddleware?: MiddlewareMetadata[];
90
78
  wireMiddleware?: CorePikkuMiddleware[];
91
79
  funcInheritedMiddleware?: MiddlewareMetadata[];
92
80
  funcMiddleware?: CorePikkuMiddleware[];
81
+ packageName?: string | null;
93
82
  }) => readonly CorePikkuMiddleware[];
@@ -64,8 +64,8 @@ export const runMiddleware = async (services, wire, middlewares, main) => {
64
64
  * ])
65
65
  * ```
66
66
  */
67
- export const addMiddleware = (tag, middleware) => {
68
- const tagGroups = pikkuState('middleware', 'tagGroup');
67
+ export const addMiddleware = (tag, middleware, packageName = null) => {
68
+ const tagGroups = pikkuState(packageName, 'middleware', 'tagGroup');
69
69
  tagGroups[tag] = middleware;
70
70
  return middleware;
71
71
  };
@@ -80,8 +80,8 @@ export const addMiddleware = (tag, middleware) => {
80
80
  *
81
81
  * @internal
82
82
  */
83
- export const getMiddlewareByName = (name) => {
84
- const middlewareStore = pikkuState('misc', 'middleware');
83
+ const getMiddlewareByName = (name) => {
84
+ const middlewareStore = pikkuState(null, 'misc', 'middleware');
85
85
  const middleware = middlewareStore[name];
86
86
  return middleware?.[0];
87
87
  };
@@ -117,7 +117,7 @@ const middlewareCache = {
117
117
  * })
118
118
  * ```
119
119
  */
120
- export const combineMiddleware = (wireType, uid, { wireInheritedMiddleware, wireMiddleware, funcInheritedMiddleware, funcMiddleware, } = {}) => {
120
+ export const combineMiddleware = (wireType, uid, { wireInheritedMiddleware, wireMiddleware, funcInheritedMiddleware, funcMiddleware, packageName = null, } = {}) => {
121
121
  if (middlewareCache[wireType][uid]) {
122
122
  return middlewareCache[wireType][uid];
123
123
  }
@@ -127,7 +127,7 @@ export const combineMiddleware = (wireType, uid, { wireInheritedMiddleware, wire
127
127
  for (const meta of wireInheritedMiddleware) {
128
128
  if (meta.type === 'http') {
129
129
  // Look up HTTP middleware group from pikkuState
130
- const group = pikkuState('middleware', 'httpGroup')[meta.route];
130
+ const group = pikkuState(packageName, 'middleware', 'httpGroup')[meta.route];
131
131
  if (group) {
132
132
  // At runtime, all factories should be resolved to middleware
133
133
  resolved.push(...group);
@@ -135,7 +135,7 @@ export const combineMiddleware = (wireType, uid, { wireInheritedMiddleware, wire
135
135
  }
136
136
  else if (meta.type === 'tag') {
137
137
  // Look up tag middleware group from pikkuState
138
- const group = pikkuState('middleware', 'tagGroup')[meta.tag];
138
+ const group = pikkuState(packageName, 'middleware', 'tagGroup')[meta.tag];
139
139
  if (group) {
140
140
  // At runtime, all factories should be resolved to middleware
141
141
  resolved.push(...group);
@@ -159,7 +159,7 @@ export const combineMiddleware = (wireType, uid, { wireInheritedMiddleware, wire
159
159
  for (const meta of funcInheritedMiddleware) {
160
160
  if (meta.type === 'tag') {
161
161
  // Look up tag middleware group from pikkuState
162
- const group = pikkuState('middleware', 'tagGroup')[meta.tag];
162
+ const group = pikkuState(packageName, 'middleware', 'tagGroup')[meta.tag];
163
163
  if (group) {
164
164
  // At runtime, all factories should be resolved to middleware
165
165
  resolved.push(...group);
@@ -1,43 +1,5 @@
1
1
  import { CoreServices, PikkuWiringTypes, PermissionMetadata, PikkuWire } from './types/core.types.js';
2
2
  import { CorePermissionGroup, CorePikkuPermission } from './function/functions.types.js';
3
- /**
4
- * 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.
5
- * @param services - The core services required for permission validation.
6
- * @param data - The data to be used in the permission validation functions.
7
- * @param wire - The wire object containing request/response context and session.
8
- * @returns A promise that resolves to void.
9
- */
10
- export declare const verifyPermissions: <Out = any>(permissions: CorePermissionGroup, services: CoreServices, data: any, wire: PikkuWire<any, never, any, never, never, never>) => Promise<boolean>;
11
- /**
12
- * Registers a single permission function by name in the global permission store.
13
- *
14
- * This function is used by CLI-generated code to register permission functions
15
- * that can be referenced by name in metadata. It stores permissions in a special
16
- * namespace to avoid conflicts with tag-based permissions.
17
- *
18
- * @param {string} name - The unique name (pikkuFuncName) of the permission function.
19
- * @param {CorePikkuPermission} permission - The permission function to register.
20
- *
21
- * @example
22
- * ```typescript
23
- * // Called by CLI-generated pikku-permissions.gen.ts
24
- * registerPermission('adminPermission_src_permissions_ts_10_5', adminPermission)
25
- * registerPermission('readPermission_src_permissions_ts_20_10', readPermission)
26
- * ```
27
- */
28
- export declare const registerPermission: (name: string, permission: CorePikkuPermission<any>) => void;
29
- /**
30
- * Retrieves a registered permission function by its name.
31
- *
32
- * This function looks up permissions that was registered with registerPermission.
33
- * It's used internally by the framework to resolve permission references in metadata.
34
- *
35
- * @param {string} name - The unique name (pikkuFuncName) of the permission function.
36
- * @returns {CorePikkuPermission | undefined} The permission function, or undefined if not found.
37
- *
38
- * @internal
39
- */
40
- export declare const getPermissionByName: (name: string) => CorePikkuPermission | undefined;
41
3
  /**
42
4
  * Adds global permissions for a specific tag.
43
5
  *
@@ -66,58 +28,12 @@ export declare const getPermissionByName: (name: string) => CorePikkuPermission
66
28
  * ])
67
29
  * ```
68
30
  */
69
- export declare const addPermission: (tag: string, permissions: CorePermissionGroup | CorePikkuPermission[]) => CorePermissionGroup | CorePikkuPermission[];
70
- /**
71
- * Retrieves permissions for a given set of tags.
72
- *
73
- * This function looks up all permissions registered for any of the provided tags
74
- * and returns them as a flattened array.
75
- *
76
- * @param {string[]} tags - Array of tags to look up permissions for.
77
- * @returns {any[]} Array of permission functions that apply to the given tags.
78
- *
79
- * @example
80
- * ```typescript
81
- * // Get all permissions for tags 'api' and 'auth'
82
- * const permissions = getPermissionsForTags(['api', 'auth'])
83
- * ```
84
- */
85
- export declare const getPermissionsForTags: (tags?: string[]) => readonly (CorePermissionGroup | CorePikkuPermission)[];
86
- /**
87
- * Combines wiring-specific permissions with function-level permissions.
88
- *
89
- * This function resolves permission metadata into actual permission functions and combines them.
90
- * It filters out wire permissions without tags from inheritedPermissions to avoid duplication
91
- * (those are passed separately as wirePermissions).
92
- *
93
- * @param {object} options - Configuration object for combining permissions.
94
- * @param {PermissionMetadata[] | undefined} options.wireInheritedPermissions - Metadata from wiring (HTTP + tags + wire with tags).
95
- * @param {CorePermissionGroup | CorePikkuPermission[] | undefined} options.wirePermissions - Inline wire permissions.
96
- * @param {PermissionMetadata[] | undefined} options.funcInheritedPermissions - Function permissions metadata (only tags).
97
- * @param {CorePermissionGroup | CorePikkuPermission[] | undefined} options.funcPermissions - Inline function permissions.
98
- * @returns {(CorePermissionGroup | CorePikkuPermission)[]} Combined array of resolved permissions.
99
- *
100
- * @example
101
- * ```typescript
102
- * const combined = combinePermissions(wireType, wireId, {
103
- * wireInheritedPermissions: meta.permissions,
104
- * wirePermissions: inlinePermissions,
105
- * funcInheritedPermissions: funcMeta.permissions,
106
- * funcPermissions: funcConfig.permissions
107
- * })
108
- * ```
109
- */
110
- export declare const combinePermissions: (wireType: PikkuWiringTypes, uid: string, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions, }?: {
111
- wireInheritedPermissions?: PermissionMetadata[];
112
- wirePermissions?: CorePermissionGroup | CorePikkuPermission[];
113
- funcInheritedPermissions?: PermissionMetadata[];
114
- funcPermissions?: CorePermissionGroup | CorePikkuPermission[];
115
- }) => readonly (CorePermissionGroup | CorePikkuPermission)[];
31
+ export declare const addPermission: (tag: string, permissions: CorePermissionGroup | CorePikkuPermission[], packageName?: string | null) => CorePermissionGroup | CorePikkuPermission[];
116
32
  /**
117
33
  * Runs permission checks using combined permissions from all sources.
118
34
  * Combines permissions from wire and function levels, then validates them.
119
35
  */
120
- export declare const runPermissions: (wireType: PikkuWiringTypes, uid: string, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions, services, wire, data, }: {
36
+ export declare const runPermissions: (wireType: PikkuWiringTypes, uid: string, { wireInheritedPermissions, wirePermissions, funcInheritedPermissions, funcPermissions, services, wire, data, packageName, }: {
121
37
  wireInheritedPermissions?: PermissionMetadata[];
122
38
  wirePermissions?: CorePermissionGroup | CorePikkuPermission[];
123
39
  funcInheritedPermissions?: PermissionMetadata[];
@@ -125,4 +41,5 @@ export declare const runPermissions: (wireType: PikkuWiringTypes, uid: string, {
125
41
  services: CoreServices;
126
42
  wire: PikkuWire<any, never, any, never, never, never>;
127
43
  data: any;
44
+ packageName?: string | null;
128
45
  }) => Promise<void>;