@pikku/core 0.12.2 → 0.12.3

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 (131) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/crypto-utils.d.ts +10 -0
  3. package/dist/crypto-utils.js +62 -0
  4. package/dist/function/function-runner.js +4 -4
  5. package/dist/function/functions.types.d.ts +26 -1
  6. package/dist/function/functions.types.js +16 -0
  7. package/dist/handle-error.d.ts +1 -1
  8. package/dist/handle-error.js +7 -3
  9. package/dist/index.d.ts +14 -2
  10. package/dist/index.js +1 -1
  11. package/dist/pikku-state.js +3 -1
  12. package/dist/schema.js +1 -1
  13. package/dist/services/in-memory-workflow-service.d.ts +8 -2
  14. package/dist/services/in-memory-workflow-service.js +28 -1
  15. package/dist/services/workflow-service.d.ts +8 -2
  16. package/dist/testing/index.d.ts +2 -0
  17. package/dist/testing/index.js +1 -0
  18. package/dist/testing/service-tests.d.ts +31 -0
  19. package/dist/testing/service-tests.js +598 -0
  20. package/dist/types/core.types.d.ts +9 -1
  21. package/dist/types/state.types.d.ts +4 -2
  22. package/dist/utils/hash.d.ts +2 -0
  23. package/dist/utils/hash.js +23 -0
  24. package/dist/wirings/ai-agent/agent-dynamic-workflow.d.ts +6 -0
  25. package/dist/wirings/ai-agent/agent-dynamic-workflow.js +348 -0
  26. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +1 -1
  27. package/dist/wirings/ai-agent/ai-agent-memory.js +6 -5
  28. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -7
  29. package/dist/wirings/ai-agent/ai-agent-prepare.js +127 -47
  30. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +4 -0
  31. package/dist/wirings/ai-agent/ai-agent-runner.js +381 -27
  32. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +7 -2
  33. package/dist/wirings/ai-agent/ai-agent-stream.js +109 -46
  34. package/dist/wirings/ai-agent/ai-agent.types.d.ts +22 -1
  35. package/dist/wirings/ai-agent/index.d.ts +1 -2
  36. package/dist/wirings/ai-agent/index.js +1 -2
  37. package/dist/wirings/channel/channel-handler.js +5 -1
  38. package/dist/wirings/channel/channel.types.d.ts +1 -7
  39. package/dist/wirings/channel/local/local-channel-handler.d.ts +1 -1
  40. package/dist/wirings/channel/local/local-channel-handler.js +5 -3
  41. package/dist/wirings/channel/local/local-channel-runner.js +14 -4
  42. package/dist/wirings/channel/serverless/serverless-channel-runner.js +4 -1
  43. package/dist/wirings/cli/cli-runner.js +10 -2
  44. package/dist/wirings/cli/cli.types.d.ts +1 -0
  45. package/dist/wirings/http/http-routes.js +0 -1
  46. package/dist/wirings/http/http-runner.d.ts +1 -1
  47. package/dist/wirings/http/http-runner.js +25 -3
  48. package/dist/wirings/http/http.types.d.ts +3 -11
  49. package/dist/wirings/http/index.d.ts +2 -1
  50. package/dist/wirings/http/index.js +1 -0
  51. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -0
  52. package/dist/wirings/http/pikku-fetch-http-request.js +3 -0
  53. package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
  54. package/dist/wirings/http/pikku-fetch-http-response.js +4 -4
  55. package/dist/wirings/http/web-request.d.ts +12 -0
  56. package/dist/wirings/http/web-request.js +85 -0
  57. package/dist/wirings/mcp/mcp-endpoint-registry.js +1 -1
  58. package/dist/wirings/mcp/mcp-runner.js +13 -1
  59. package/dist/wirings/rpc/rpc-runner.d.ts +30 -6
  60. package/dist/wirings/rpc/rpc-runner.js +36 -14
  61. package/dist/wirings/rpc/rpc-types.d.ts +6 -1
  62. package/dist/wirings/rpc/wire-addon.d.ts +1 -0
  63. package/dist/wirings/rpc/wire-addon.js +1 -1
  64. package/dist/wirings/scheduler/scheduler-runner.js +1 -0
  65. package/dist/wirings/workflow/graph/graph-validation.d.ts +3 -0
  66. package/dist/wirings/workflow/graph/graph-validation.js +175 -0
  67. package/dist/wirings/workflow/graph/index.d.ts +1 -0
  68. package/dist/wirings/workflow/graph/index.js +1 -0
  69. package/dist/wirings/workflow/index.d.ts +1 -1
  70. package/dist/wirings/workflow/pikku-workflow-service.d.ts +8 -2
  71. package/dist/wirings/workflow/pikku-workflow-service.js +1 -2
  72. package/dist/wirings/workflow/workflow.types.d.ts +10 -1
  73. package/package.json +4 -2
  74. package/src/crypto-utils.test.ts +99 -1
  75. package/src/crypto-utils.ts +114 -0
  76. package/src/function/function-runner.ts +5 -5
  77. package/src/function/functions.types.ts +38 -1
  78. package/src/handle-error.test.ts +65 -2
  79. package/src/handle-error.ts +8 -4
  80. package/src/index.ts +14 -0
  81. package/src/pikku-state.ts +3 -1
  82. package/src/schema.ts +1 -1
  83. package/src/services/in-memory-workflow-service.ts +45 -2
  84. package/src/services/workflow-service.ts +12 -1
  85. package/src/testing/index.ts +2 -0
  86. package/src/testing/service-tests.ts +873 -0
  87. package/src/types/core.types.ts +9 -1
  88. package/src/types/state.types.ts +4 -2
  89. package/src/utils/hash.test.ts +68 -0
  90. package/src/utils/hash.ts +26 -0
  91. package/src/wirings/ai-agent/agent-dynamic-workflow.ts +469 -0
  92. package/src/wirings/ai-agent/ai-agent-memory.ts +7 -6
  93. package/src/wirings/ai-agent/ai-agent-prepare.ts +175 -61
  94. package/src/wirings/ai-agent/ai-agent-runner.test.ts +3 -1
  95. package/src/wirings/ai-agent/ai-agent-runner.ts +553 -31
  96. package/src/wirings/ai-agent/ai-agent-stream.test.ts +209 -2
  97. package/src/wirings/ai-agent/ai-agent-stream.ts +182 -89
  98. package/src/wirings/ai-agent/ai-agent.types.ts +23 -1
  99. package/src/wirings/ai-agent/index.ts +1 -5
  100. package/src/wirings/channel/channel-handler.ts +11 -2
  101. package/src/wirings/channel/channel.types.ts +1 -7
  102. package/src/wirings/channel/local/local-channel-handler.ts +5 -3
  103. package/src/wirings/channel/local/local-channel-runner.ts +17 -7
  104. package/src/wirings/channel/serverless/serverless-channel-runner.ts +4 -1
  105. package/src/wirings/cli/cli-runner.ts +12 -2
  106. package/src/wirings/cli/cli.types.ts +1 -0
  107. package/src/wirings/http/http-routes.ts +0 -1
  108. package/src/wirings/http/http-runner.ts +35 -10
  109. package/src/wirings/http/http.types.ts +3 -12
  110. package/src/wirings/http/index.ts +3 -0
  111. package/src/wirings/http/pikku-fetch-http-request.ts +4 -0
  112. package/src/wirings/http/pikku-fetch-http-response.ts +4 -4
  113. package/src/wirings/http/web-request.test.ts +236 -0
  114. package/src/wirings/http/web-request.ts +104 -0
  115. package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
  116. package/src/wirings/mcp/mcp-runner.ts +30 -12
  117. package/src/wirings/rpc/rpc-runner.ts +45 -24
  118. package/src/wirings/rpc/rpc-types.ts +6 -1
  119. package/src/wirings/rpc/wire-addon.ts +2 -1
  120. package/src/wirings/scheduler/scheduler-runner.ts +1 -0
  121. package/src/wirings/workflow/graph/graph-validation.test.ts +170 -0
  122. package/src/wirings/workflow/graph/graph-validation.ts +237 -0
  123. package/src/wirings/workflow/graph/index.ts +5 -0
  124. package/src/wirings/workflow/index.ts +1 -0
  125. package/src/wirings/workflow/pikku-workflow-service.ts +14 -3
  126. package/src/wirings/workflow/workflow.types.ts +9 -1
  127. package/tsconfig.tsbuildinfo +1 -1
  128. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +0 -5
  129. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +0 -168
  130. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +0 -363
  131. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +0 -238
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ## 0.12.0
2
2
 
3
+ ## 0.12.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 387b2ee: Add approval descriptions, rename requiresApproval to approvalRequired, export all service interfaces, add exposeErrors option to HTTP runner, promote addons to top-level state, add packageName to CommonWireMeta, add errors to function config, and improve agent runner streaming
8
+ - 32ed003: Add envelope encryption utilities and database-backed secret services with KEK rotation support
9
+ - 7d369f3: Fix agent sub-agent tool execution failures: use UUID for sub-agent thread IDs (was exceeding varchar(36) DB column), and synthesize error results for failed tool calls in non-streaming run() to prevent "Tool result is missing" cascading errors.
10
+ - 508a796: Fix MCP server not exposing addon tools: resolve namespaced function IDs in MCP runner, load addon schemas after schema generation, and use resolveFunctionMeta for MCP JSON serialization
11
+ - ffe83af: Add Web Response passthrough support and fix close() flushing
12
+
13
+ - HTTP runner detects when a function returns a Web `Response` object and applies it directly via `applyWebResponse()`, enabling seamless integration with libraries like Auth.js
14
+ - Add `send()` method to `PikkuHTTPResponse` for setting body without Content-Type headers
15
+ - Add `headers()` method to `PikkuHTTPRequest` for retrieving all headers as a record
16
+ - Add `toWebRequest()` and `applyWebResponse()` utilities for Web Request/Response conversion
17
+ - Fix `close()` in Express, Fastify, and UWS responses to flush buffered status/headers/body before ending the connection
18
+
19
+ - c7ff141: Add WorkflowVersionStatus type with draft→active lifecycle for AI-generated workflows, type all DB status fields with proper unions instead of plain strings
20
+
3
21
  ## 0.12.2
4
22
 
5
23
  ### Patch Changes
@@ -1,2 +1,12 @@
1
1
  export declare const encryptJSON: (secret: string, value: unknown) => Promise<string>;
2
2
  export declare const decryptJSON: <T>(secret: string, token: string) => Promise<T>;
3
+ export declare const generateDEK: () => Promise<string>;
4
+ export declare const wrapDEK: (kek: string, plaintextDEK: string) => Promise<string>;
5
+ export declare const unwrapDEK: (kek: string, wrappedDEK: string) => Promise<string>;
6
+ export interface EnvelopeEncryptResult {
7
+ ciphertext: string;
8
+ wrappedDEK: string;
9
+ }
10
+ export declare const envelopeEncrypt: (kek: string, value: unknown) => Promise<EnvelopeEncryptResult>;
11
+ export declare const envelopeDecrypt: <T>(kek: string, ciphertext: string, wrappedDEK: string) => Promise<T>;
12
+ export declare const envelopeRewrap: (oldKEK: string, newKEK: string, wrappedDEK: string) => Promise<string>;
@@ -76,3 +76,65 @@ export const decryptJSON = async (secret, token) => {
76
76
  const decrypted = await subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);
77
77
  return JSON.parse(decoder.decode(new Uint8Array(decrypted)));
78
78
  };
79
+ /**
80
+ * Envelope encryption utilities.
81
+ *
82
+ * Each secret gets its own random DEK (data encryption key).
83
+ * The DEK is wrapped (encrypted) by a KEK (key encryption key) — typically an env var.
84
+ * The actual secret is encrypted with the DEK.
85
+ *
86
+ * KEK rotation only re-wraps the DEK, never touches the ciphertext.
87
+ */
88
+ const importRawKey = async (rawBytes) => {
89
+ const subtle = getSubtle();
90
+ return subtle.importKey('raw', rawBytes.buffer, { name: 'AES-GCM' }, true, ['encrypt', 'decrypt']);
91
+ };
92
+ export const generateDEK = async () => {
93
+ const raw = globalThis.crypto.getRandomValues(new Uint8Array(32));
94
+ return toBase64Url(raw);
95
+ };
96
+ export const wrapDEK = async (kek, plaintextDEK) => {
97
+ return encryptJSON(kek, plaintextDEK);
98
+ };
99
+ export const unwrapDEK = async (kek, wrappedDEK) => {
100
+ return decryptJSON(kek, wrappedDEK);
101
+ };
102
+ const encryptWithDEK = async (dekBase64, value) => {
103
+ const crypto = globalThis.crypto;
104
+ const subtle = getSubtle();
105
+ const iv = crypto.getRandomValues(new Uint8Array(12));
106
+ const key = await importRawKey(fromBase64Url(dekBase64));
107
+ const plaintext = encoder.encode(JSON.stringify(value));
108
+ const encrypted = await subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext);
109
+ const cipherBytes = new Uint8Array(encrypted);
110
+ const out = new Uint8Array(iv.length + cipherBytes.length);
111
+ out.set(iv, 0);
112
+ out.set(cipherBytes, iv.length);
113
+ return toBase64Url(out);
114
+ };
115
+ const decryptWithDEK = async (dekBase64, token) => {
116
+ const subtle = getSubtle();
117
+ const data = fromBase64Url(token);
118
+ if (data.length < 13) {
119
+ throw new Error('Invalid encrypted payload');
120
+ }
121
+ const iv = data.slice(0, 12);
122
+ const ciphertext = data.slice(12);
123
+ const key = await importRawKey(fromBase64Url(dekBase64));
124
+ const decrypted = await subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);
125
+ return JSON.parse(decoder.decode(new Uint8Array(decrypted)));
126
+ };
127
+ export const envelopeEncrypt = async (kek, value) => {
128
+ const dek = await generateDEK();
129
+ const ciphertext = await encryptWithDEK(dek, value);
130
+ const wrappedDEK = await wrapDEK(kek, dek);
131
+ return { ciphertext, wrappedDEK };
132
+ };
133
+ export const envelopeDecrypt = async (kek, ciphertext, wrappedDEK) => {
134
+ const dek = await unwrapDEK(kek, wrappedDEK);
135
+ return decryptWithDEK(dek, ciphertext);
136
+ };
137
+ export const envelopeRewrap = async (oldKEK, newKEK, wrappedDEK) => {
138
+ const dek = await unwrapDEK(oldKEK, wrappedDEK);
139
+ return wrapDEK(newKEK, dek);
140
+ };
@@ -50,7 +50,7 @@ export const getAllFunctionNames = () => {
50
50
  const functions = [];
51
51
  const mainFunctionsMeta = pikkuState(null, 'function', 'meta');
52
52
  functions.push(...Object.keys(mainFunctionsMeta));
53
- const addons = pikkuState(null, 'rpc', 'addons');
53
+ const addons = pikkuState(null, 'addons', 'packages');
54
54
  for (const [namespace, config] of addons) {
55
55
  const packageFunctionsMeta = pikkuState(config.package, 'function', 'meta');
56
56
  for (const funcName of Object.keys(packageFunctionsMeta)) {
@@ -166,12 +166,12 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
166
166
  // Validate and coerce data if schema is defined
167
167
  const inputSchemaName = funcMeta.inputSchemaName;
168
168
  if (inputSchemaName) {
169
- // Validate request data against the defined schema, if any
170
- await validateSchema(resolvedSingletonServices.logger, resolvedSingletonServices.schema, inputSchemaName, actualData, packageName);
171
- // Coerce (top level) query string parameters or date objects if specified by the schema
169
+ // Coerce (top level) data types before validation (e.g. string→array, string→date)
172
170
  if (coerceDataFromSchema) {
173
171
  coerceTopLevelDataFromSchema(inputSchemaName, actualData, packageName);
174
172
  }
173
+ // Validate request data against the defined schema, if any
174
+ await validateSchema(resolvedSingletonServices.logger, resolvedSingletonServices.schema, inputSchemaName, actualData, packageName);
175
175
  }
176
176
  if (mergedInheritedPermissions.length > 0 ||
177
177
  wirePermissions ||
@@ -1,5 +1,6 @@
1
1
  import type { CoreServices, CoreSingletonServices, CoreUserSession, CorePikkuMiddleware, PikkuWire, PickRequired } from '../types/core.types.js';
2
2
  import type { StandardSchemaV1 } from '@standard-schema/spec';
3
+ import type { PikkuError } from '../errors/error-handler.js';
3
4
  import type { CoreNodeConfig } from '../wirings/node/node.types.js';
4
5
  /**
5
6
  * @deprecated Use StandardSchemaV1 from @standard-schema/spec instead.
@@ -103,6 +104,28 @@ export type CorePikkuPermissionFactory<In = any, Services extends CoreSingletonS
103
104
  * ```
104
105
  */
105
106
  export declare const pikkuPermissionFactory: <In = any>(factory: CorePikkuPermissionFactory<In>) => CorePikkuPermissionFactory<In>;
107
+ /**
108
+ * A function that generates a human-readable description of a pending approval action.
109
+ * Used by AI agents to show meaningful approval prompts instead of raw tool arguments.
110
+ *
111
+ * @template In - The input type (same as the function it describes).
112
+ * @template Services - The services type, defaults to `CoreSingletonServices`.
113
+ */
114
+ export type CorePikkuApprovalDescription<In = any, Services extends CoreSingletonServices = CoreSingletonServices> = (services: Services, data: In) => Promise<string>;
115
+ /**
116
+ * Factory function for creating approval description functions with tree-shaking support.
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * export const deleteTodoApproval = pikkuApprovalDescription(
121
+ * async ({ todoStore }, { id }) => {
122
+ * const todo = await todoStore.get(id)
123
+ * return `Delete todo: "${todo.title}"`
124
+ * }
125
+ * )
126
+ * ```
127
+ */
128
+ export declare const pikkuApprovalDescription: <In = any, Services extends CoreSingletonServices = CoreSingletonServices>(fn: CorePikkuApprovalDescription<In, Services>) => CorePikkuApprovalDescription<In, Services>;
106
129
  export type CorePikkuAuth<Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = (services: Services, session: Session) => Promise<boolean> | boolean;
107
130
  export type CorePikkuAuthConfig<Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = {
108
131
  func: CorePikkuAuth<Services, Session>;
@@ -123,7 +146,8 @@ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any,
123
146
  remote?: boolean;
124
147
  mcp?: boolean;
125
148
  readonly?: boolean;
126
- requiresApproval?: boolean;
149
+ approvalRequired?: boolean;
150
+ approvalDescription?: any;
127
151
  func: PikkuFunction;
128
152
  auth?: boolean;
129
153
  permissions?: CorePermissionGroup<PikkuPermission>;
@@ -131,4 +155,5 @@ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any,
131
155
  input?: InputSchema;
132
156
  output?: OutputSchema;
133
157
  node?: CoreNodeConfig;
158
+ errors?: Array<typeof PikkuError>;
134
159
  };
@@ -49,6 +49,22 @@ export const pikkuPermission = (permission) => {
49
49
  export const pikkuPermissionFactory = (factory) => {
50
50
  return factory;
51
51
  };
52
+ /**
53
+ * Factory function for creating approval description functions with tree-shaking support.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * export const deleteTodoApproval = pikkuApprovalDescription(
58
+ * async ({ todoStore }, { id }) => {
59
+ * const todo = await todoStore.get(id)
60
+ * return `Delete todo: "${todo.title}"`
61
+ * }
62
+ * )
63
+ * ```
64
+ */
65
+ export const pikkuApprovalDescription = (fn) => {
66
+ return fn;
67
+ };
52
68
  export const pikkuAuth = (auth) => {
53
69
  const fn = typeof auth === 'function' ? auth : auth.func;
54
70
  const wrapper = async (services, _data, wire) => {
@@ -11,4 +11,4 @@ import type { PikkuHTTP } from './wirings/http/http.types.js';
11
11
  * @param {boolean} respondWith404 - Whether to respond with 404 for NotFoundError
12
12
  * @param {boolean} bubbleError - Whether to throw the error after handling
13
13
  */
14
- export declare const handleHTTPError: (e: any, http: PikkuHTTP | undefined, trackerId: string | undefined, logger: Logger, logWarningsForStatusCodes: number[], respondWith404: boolean, bubbleError: boolean) => void;
14
+ export declare const handleHTTPError: (e: any, http: PikkuHTTP | undefined, trackerId: string | undefined, logger: Logger, logWarningsForStatusCodes: number[], respondWith404: boolean, bubbleError: boolean, exposeErrors?: boolean) => void;
@@ -11,7 +11,7 @@ import { NotFoundError } from './errors/errors.js';
11
11
  * @param {boolean} respondWith404 - Whether to respond with 404 for NotFoundError
12
12
  * @param {boolean} bubbleError - Whether to throw the error after handling
13
13
  */
14
- export const handleHTTPError = (e, http, trackerId, logger, logWarningsForStatusCodes, respondWith404, bubbleError) => {
14
+ export const handleHTTPError = (e, http, trackerId, logger, logWarningsForStatusCodes, respondWith404, bubbleError, exposeErrors = false) => {
15
15
  // Skip 404 handling if configured to do so
16
16
  if (e instanceof NotFoundError && !respondWith404) {
17
17
  return;
@@ -40,11 +40,15 @@ export const handleHTTPError = (e, http, trackerId, logger, logWarningsForStatus
40
40
  http?.response?.status(500);
41
41
  if (trackerId) {
42
42
  logger.warn(`Error id: ${trackerId}`);
43
- http?.response?.json({ errorId: trackerId });
43
+ const errorBody = { errorId: trackerId };
44
+ if (exposeErrors && e instanceof Error) {
45
+ errorBody.message = e.message;
46
+ errorBody.stack = e.stack;
47
+ }
48
+ http?.response?.json(errorBody);
44
49
  }
45
50
  }
46
51
  if (bubbleError) {
47
52
  throw e;
48
53
  }
49
- http?.response?.close?.();
50
54
  };
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@
3
3
  */
4
4
  export type { CommonWireMeta, CoreConfig, CorePikkuMiddleware, CorePikkuMiddlewareConfig, CorePikkuMiddlewareFactory, CorePikkuMiddlewareGroup, CoreServices, CoreSingletonServices, CoreUserSession, CreateConfig, FunctionMeta, FunctionRuntimeMeta, FunctionServicesMeta, FunctionWiresMeta, FunctionsMeta, FunctionsRuntimeMeta, JSONPrimitive, JSONValue, MakeRequired, MiddlewareMetadata, PermissionMetadata, PickOptional, PickRequired, PikkuAIMiddlewareHooks, PikkuWire, PikkuWiringTypes, RequireAtLeastOne, SerializedError, WireServices, } from './types/core.types.js';
5
5
  export { pikkuAIMiddleware, pikkuChannelMiddleware, pikkuChannelMiddlewareFactory, pikkuMiddleware, pikkuMiddlewareFactory, } from './types/core.types.js';
6
- export type { CorePikkuAuth, CorePikkuAuthConfig, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuPermission, CorePikkuPermissionConfig, CorePikkuPermissionFactory, CorePermissionGroup, ZodLike, } from './function/functions.types.js';
7
- export { pikkuAuth, pikkuPermission, pikkuPermissionFactory, } from './function/functions.types.js';
6
+ export type { CorePikkuAuth, CorePikkuAuthConfig, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuPermission, CorePikkuPermissionConfig, CorePikkuPermissionFactory, CorePikkuApprovalDescription, CorePermissionGroup, ZodLike, } from './function/functions.types.js';
7
+ export { pikkuAuth, pikkuPermission, pikkuPermissionFactory, pikkuApprovalDescription, } from './function/functions.types.js';
8
8
  export { addFunction, getAllFunctionNames } from './function/index.js';
9
9
  export { PikkuRequest } from './pikku-request.js';
10
10
  export { getRelativeTimeOffsetFromNow, parseDurationString, } from './time-utils.js';
@@ -21,6 +21,18 @@ export { NotFoundError } from './errors/errors.js';
21
21
  export type { EventHubService } from './wirings/channel/eventhub-service.js';
22
22
  export type { QueueService } from './wirings/queue/queue.types.js';
23
23
  export type { JWTService } from './services/jwt-service.js';
24
+ export type { SecretService } from './services/secret-service.js';
25
+ export type { VariablesService } from './services/variables-service.js';
26
+ export type { ContentService } from './services/content-service.js';
27
+ export type { DeploymentService } from './services/deployment-service.js';
28
+ export type { WorkflowService } from './services/workflow-service.js';
29
+ export type { GatewayService } from './services/gateway-service.js';
30
+ export type { TriggerService } from './services/trigger-service.js';
31
+ export type { SchemaService } from './services/schema-service.js';
32
+ export type { SessionService } from './services/user-session-service.js';
33
+ export type { AIAgentRunnerService } from './services/ai-agent-runner-service.js';
34
+ export type { AIRunStateService } from './services/ai-run-state-service.js';
35
+ export type { AIStorageService } from './services/ai-storage-service.js';
24
36
  export type { HTTPMethod } from './wirings/http/http.types.js';
25
37
  export type { GraphNodeConfig } from './wirings/workflow/graph/workflow-graph.types.js';
26
38
  export { createGraph } from './wirings/workflow/graph/graph-node.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { pikkuAIMiddleware, pikkuChannelMiddleware, pikkuChannelMiddlewareFactory, pikkuMiddleware, pikkuMiddlewareFactory, } from './types/core.types.js';
2
- export { pikkuAuth, pikkuPermission, pikkuPermissionFactory, } from './function/functions.types.js';
2
+ export { pikkuAuth, pikkuPermission, pikkuPermissionFactory, pikkuApprovalDescription, } from './function/functions.types.js';
3
3
  export { addFunction, getAllFunctionNames } from './function/index.js';
4
4
  export { PikkuRequest } from './pikku-request.js';
5
5
  export { getRelativeTimeOffsetFromNow, parseDurationString, } from './time-utils.js';
@@ -42,7 +42,9 @@ const createEmptyPackageState = () => ({
42
42
  rpc: {
43
43
  meta: {},
44
44
  files: new Map(),
45
- addons: new Map(),
45
+ },
46
+ addons: {
47
+ packages: new Map(),
46
48
  },
47
49
  http: {
48
50
  middleware: new Map(),
package/dist/schema.js CHANGED
@@ -104,6 +104,6 @@ export const validateSchema = async (logger, schemaService, schemaName, data, pa
104
104
  throw new MissingSchemaError(`Schema '${schemaName}' not found. Ensure schema generation has been run.`);
105
105
  }
106
106
  await schemaService.compileSchema(key, schema);
107
- await schemaService.validateSchema(key, data);
107
+ await schemaService.validateSchema(key, data ?? {});
108
108
  }
109
109
  };
@@ -1,6 +1,6 @@
1
1
  import { PikkuWorkflowService } from '../wirings/workflow/pikku-workflow-service.js';
2
2
  import type { SerializedError } from '../types/core.types.js';
3
- import type { WorkflowRun, WorkflowRunWire, StepState, WorkflowStatus, WorkflowStepOptions } from '../wirings/workflow/workflow.types.js';
3
+ import type { WorkflowRun, WorkflowRunWire, StepState, WorkflowStatus, WorkflowVersionStatus, WorkflowStepOptions } from '../wirings/workflow/workflow.types.js';
4
4
  /**
5
5
  * In-memory implementation of WorkflowService for inline-only execution
6
6
  *
@@ -51,9 +51,15 @@ export declare class InMemoryWorkflowService extends PikkuWorkflowService {
51
51
  setBranchTaken(stepId: string, branchKey: string): Promise<void>;
52
52
  updateRunState(runId: string, name: string, value: unknown): Promise<void>;
53
53
  getRunState(runId: string): Promise<Record<string, unknown>>;
54
- upsertWorkflowVersion(name: string, graphHash: string, graph: any, source: string): Promise<void>;
54
+ upsertWorkflowVersion(name: string, graphHash: string, graph: any, source: string, status?: WorkflowVersionStatus): Promise<void>;
55
+ updateWorkflowVersionStatus(name: string, graphHash: string, status: WorkflowVersionStatus): Promise<void>;
55
56
  getWorkflowVersion(name: string, graphHash: string): Promise<{
56
57
  graph: any;
57
58
  source: string;
58
59
  } | null>;
60
+ getAIGeneratedWorkflows(agentName?: string): Promise<Array<{
61
+ workflowName: string;
62
+ graphHash: string;
63
+ graph: any;
64
+ }>>;
59
65
  }
@@ -272,16 +272,43 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
272
272
  async getRunState(runId) {
273
273
  return this.runState.get(runId) || {};
274
274
  }
275
- async upsertWorkflowVersion(name, graphHash, graph, source) {
275
+ async upsertWorkflowVersion(name, graphHash, graph, source, status) {
276
276
  this.workflowVersions.set(`${name}:${graphHash}`, {
277
277
  graph,
278
278
  source,
279
+ status: status ?? 'active',
279
280
  });
280
281
  }
282
+ async updateWorkflowVersionStatus(name, graphHash, status) {
283
+ const key = `${name}:${graphHash}`;
284
+ const version = this.workflowVersions.get(key);
285
+ if (version) {
286
+ version.status = status;
287
+ }
288
+ }
281
289
  async getWorkflowVersion(name, graphHash) {
282
290
  const version = this.workflowVersions.get(`${name}:${graphHash}`);
283
291
  if (!version)
284
292
  return null;
285
293
  return { graph: version.graph, source: version.source };
286
294
  }
295
+ async getAIGeneratedWorkflows(agentName) {
296
+ const results = [];
297
+ const prefix = agentName ? `ai:${agentName}:` : 'ai:';
298
+ for (const [key, value] of this.workflowVersions) {
299
+ if (value.source !== 'ai-agent' || value.status !== 'active')
300
+ continue;
301
+ const separatorIdx = key.lastIndexOf(':');
302
+ const wfName = key.substring(0, separatorIdx);
303
+ const hash = key.substring(separatorIdx + 1);
304
+ if (wfName.startsWith(prefix)) {
305
+ results.push({
306
+ workflowName: wfName,
307
+ graphHash: hash,
308
+ graph: value.graph,
309
+ });
310
+ }
311
+ }
312
+ return results;
313
+ }
287
314
  }
@@ -1,5 +1,5 @@
1
1
  import type { SerializedError } from '../types/core.types.js';
2
- import type { WorkflowRun, WorkflowRunWire, StepState, WorkflowStatus } from '../wirings/workflow/workflow.types.js';
2
+ import type { WorkflowRun, WorkflowRunWire, StepState, WorkflowStatus, WorkflowVersionStatus } from '../wirings/workflow/workflow.types.js';
3
3
  /**
4
4
  * Interface for workflow orchestration
5
5
  * Handles workflow execution, replay, orchestration logic, and run-level state
@@ -34,9 +34,15 @@ export interface WorkflowService {
34
34
  setStepError(stepId: string, error: Error): Promise<void>;
35
35
  createRetryAttempt(stepId: string, status: 'pending' | 'running'): Promise<StepState>;
36
36
  executeWorkflowStep(runId: string, stepName: string, rpcName: string | null, data: any, rpcService: any): Promise<void>;
37
- upsertWorkflowVersion(name: string, graphHash: string, graph: any, source: string): Promise<void>;
37
+ upsertWorkflowVersion(name: string, graphHash: string, graph: any, source: string, status?: WorkflowVersionStatus): Promise<void>;
38
+ updateWorkflowVersionStatus(name: string, graphHash: string, status: WorkflowVersionStatus): Promise<void>;
38
39
  getWorkflowVersion(name: string, graphHash: string): Promise<{
39
40
  graph: any;
40
41
  source: string;
41
42
  } | null>;
43
+ getAIGeneratedWorkflows(agentName?: string): Promise<Array<{
44
+ workflowName: string;
45
+ graphHash: string;
46
+ graph: any;
47
+ }>>;
42
48
  }
@@ -0,0 +1,2 @@
1
+ export { defineServiceTests } from './service-tests.js';
2
+ export type { ServiceTestConfig } from './service-tests.js';
@@ -0,0 +1 @@
1
+ export { defineServiceTests } from './service-tests.js';
@@ -0,0 +1,31 @@
1
+ import type { ChannelStore } from '../wirings/channel/channel-store.js';
2
+ import type { EventHubStore } from '../wirings/channel/eventhub-store.js';
3
+ import type { PikkuWorkflowService } from '../wirings/workflow/pikku-workflow-service.js';
4
+ import type { WorkflowRunService } from '../wirings/workflow/workflow.types.js';
5
+ import type { DeploymentService } from '../services/deployment-service.js';
6
+ import type { AIStorageService } from '../services/ai-storage-service.js';
7
+ import type { AIRunStateService } from '../services/ai-run-state-service.js';
8
+ import type { SecretService } from '../services/secret-service.js';
9
+ import type { AgentRunService } from '../wirings/ai-agent/ai-agent.types.js';
10
+ export interface ServiceTestConfig {
11
+ name: string;
12
+ services: {
13
+ channelStore?: () => Promise<ChannelStore>;
14
+ eventHubStore?: () => Promise<EventHubStore<Record<string, any>>>;
15
+ workflowService?: () => Promise<PikkuWorkflowService>;
16
+ workflowRunService?: () => Promise<WorkflowRunService>;
17
+ deploymentService?: () => Promise<DeploymentService & {
18
+ stop(): Promise<void>;
19
+ }>;
20
+ aiStorageService?: () => Promise<AIStorageService & AIRunStateService>;
21
+ agentRunService?: () => Promise<AgentRunService>;
22
+ secretService?: (config: {
23
+ key: string;
24
+ keyVersion?: number;
25
+ previousKey?: string;
26
+ }) => Promise<SecretService & {
27
+ rotateKEK?(): Promise<number>;
28
+ }>;
29
+ };
30
+ }
31
+ export declare function defineServiceTests(config: ServiceTestConfig): void;