@pikku/core 0.12.14 → 0.12.16
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.
- package/CHANGELOG.md +36 -0
- package/dist/errors/errors.d.ts +4 -0
- package/dist/errors/errors.js +12 -0
- package/dist/function/function-runner.js +2 -1
- package/dist/function/functions.types.js +1 -0
- package/dist/function/index.d.ts +2 -1
- package/dist/function/index.js +1 -0
- package/dist/handle-error.d.ts +2 -2
- package/dist/handle-error.js +8 -8
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -2
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +3 -0
- package/dist/middleware/remote-auth.js +5 -2
- package/dist/middleware/telemetry.d.ts +47 -0
- package/dist/middleware/telemetry.js +106 -0
- package/dist/middleware-runner.js +31 -4
- package/dist/permissions.d.ts +13 -1
- package/dist/permissions.js +51 -0
- package/dist/pikku-state.d.ts +0 -1
- package/dist/pikku-state.js +1 -4
- package/dist/remote.d.ts +10 -0
- package/dist/remote.js +32 -0
- package/dist/schema.js +2 -0
- package/dist/services/deployment-service.d.ts +12 -1
- package/dist/services/in-memory-queue-service.d.ts +7 -0
- package/dist/services/in-memory-queue-service.js +28 -0
- package/dist/services/index.d.ts +4 -1
- package/dist/services/index.js +2 -1
- package/dist/services/logger-console.d.ts +26 -40
- package/dist/services/logger-console.js +102 -46
- package/dist/services/logger.d.ts +5 -0
- package/dist/services/meta-service.d.ts +175 -0
- package/dist/services/meta-service.js +310 -0
- package/dist/services/workflow-service.d.ts +6 -1
- package/dist/testing/service-tests.js +0 -8
- package/dist/types/core.types.d.ts +21 -0
- package/dist/types/core.types.js +7 -1
- package/dist/types/state.types.d.ts +2 -2
- package/dist/wirings/ai-agent/ai-agent-prepare.js +42 -21
- package/dist/wirings/ai-agent/ai-agent-registry.js +2 -2
- package/dist/wirings/ai-agent/ai-agent-runner.js +18 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +1 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +5 -3
- package/dist/wirings/channel/channel-runner.js +3 -3
- package/dist/wirings/cli/cli-runner.js +5 -3
- package/dist/wirings/cli/command-parser.js +7 -3
- package/dist/wirings/http/http-runner.d.ts +1 -1
- package/dist/wirings/http/http-runner.js +23 -11
- package/dist/wirings/http/http.types.d.ts +3 -0
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-response.js +3 -0
- package/dist/wirings/mcp/mcp-runner.js +5 -3
- package/dist/wirings/mcp/mcp.types.d.ts +1 -1
- package/dist/wirings/queue/queue-runner.d.ts +3 -1
- package/dist/wirings/queue/queue-runner.js +7 -3
- package/dist/wirings/rpc/rpc-runner.js +56 -90
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -1
- package/dist/wirings/scheduler/scheduler-runner.js +9 -5
- package/dist/wirings/trigger/trigger-runner.js +4 -2
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +1 -1
- package/dist/wirings/workflow/dsl/workflow-runner.js +6 -9
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -1
- package/dist/wirings/workflow/graph/graph-runner.js +18 -4
- package/dist/wirings/workflow/index.d.ts +4 -2
- package/dist/wirings/workflow/index.js +4 -2
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +16 -4
- package/dist/wirings/workflow/pikku-workflow-service.js +216 -24
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +40 -0
- package/dist/wirings/workflow/workflow-queue-workers.js +41 -0
- package/dist/wirings/workflow/workflow.types.d.ts +17 -1
- package/package.json +4 -1
- package/src/errors/errors.ts +12 -0
- package/src/function/function-runner.ts +5 -4
- package/src/function/functions.types.ts +1 -0
- package/src/function/index.ts +10 -0
- package/src/handle-error.test.ts +2 -2
- package/src/handle-error.ts +8 -8
- package/src/index.ts +2 -2
- package/src/middleware/index.ts +3 -0
- package/src/middleware/remote-auth.test.ts +4 -4
- package/src/middleware/remote-auth.ts +7 -2
- package/src/middleware/telemetry.ts +110 -0
- package/src/middleware-runner.test.ts +149 -1
- package/src/middleware-runner.ts +48 -4
- package/src/permissions.ts +70 -0
- package/src/pikku-state.test.ts +0 -26
- package/src/pikku-state.ts +1 -5
- package/src/remote.ts +46 -0
- package/src/schema.ts +1 -0
- package/src/services/deployment-service.ts +17 -1
- package/src/services/in-memory-queue-service.ts +46 -0
- package/src/services/index.ts +21 -1
- package/src/services/logger-console.ts +127 -47
- package/src/services/logger.ts +6 -0
- package/src/services/meta-service.ts +523 -0
- package/src/services/workflow-service.ts +8 -0
- package/src/testing/service-tests.ts +0 -10
- package/src/types/core.types.ts +36 -1
- package/src/types/state.types.ts +2 -2
- package/src/wirings/ai-agent/ai-agent-prepare.ts +51 -40
- package/src/wirings/ai-agent/ai-agent-registry.ts +3 -3
- package/src/wirings/ai-agent/ai-agent-runner.ts +16 -1
- package/src/wirings/ai-agent/ai-agent-stream.ts +8 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +5 -3
- package/src/wirings/channel/channel-runner.ts +4 -5
- package/src/wirings/channel/local/local-channel-runner.test.ts +5 -1
- package/src/wirings/cli/cli-runner.test.ts +8 -7
- package/src/wirings/cli/cli-runner.ts +6 -4
- package/src/wirings/cli/command-parser.ts +8 -3
- package/src/wirings/http/http-runner.ts +27 -11
- package/src/wirings/http/http.types.ts +3 -0
- package/src/wirings/http/pikku-fetch-http-response.ts +4 -0
- package/src/wirings/mcp/mcp-runner.ts +7 -9
- package/src/wirings/mcp/mcp.types.ts +1 -1
- package/src/wirings/queue/queue-runner.test.ts +5 -11
- package/src/wirings/queue/queue-runner.ts +11 -3
- package/src/wirings/rpc/rpc-runner.ts +82 -115
- package/src/wirings/scheduler/scheduler-runner.test.ts +5 -11
- package/src/wirings/scheduler/scheduler-runner.ts +13 -5
- package/src/wirings/trigger/trigger-runner.test.ts +10 -11
- package/src/wirings/trigger/trigger-runner.ts +6 -4
- package/src/wirings/workflow/dsl/workflow-runner.ts +11 -10
- package/src/wirings/workflow/graph/graph-runner.ts +19 -4
- package/src/wirings/workflow/index.ts +17 -6
- package/src/wirings/workflow/pikku-workflow-service.ts +284 -24
- package/src/wirings/workflow/workflow-queue-workers.ts +85 -0
- package/src/wirings/workflow/workflow.types.ts +16 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/ai-agent/agent-dynamic-workflow.d.ts +0 -6
- package/dist/wirings/ai-agent/agent-dynamic-workflow.js +0 -468
- package/dist/wirings/workflow/workflow-helpers.d.ts +0 -36
- package/dist/wirings/workflow/workflow-helpers.js +0 -38
- package/src/wirings/ai-agent/agent-dynamic-workflow.ts +0 -610
- package/src/wirings/workflow/workflow-helpers.test.ts +0 -129
- package/src/wirings/workflow/workflow-helpers.ts +0 -79
|
@@ -7,7 +7,6 @@ import { ForbiddenError } from '../../errors/errors.js'
|
|
|
7
7
|
import { PikkuError, addError } from '../../errors/error-handler.js'
|
|
8
8
|
import type { PikkuRPC, ResolvedFunction } from './rpc-types.js'
|
|
9
9
|
import { parseVersionedId } from '../../version.js'
|
|
10
|
-
import { encryptJSON } from '../../crypto-utils.js'
|
|
11
10
|
|
|
12
11
|
export class RPCNotFoundError extends PikkuError {
|
|
13
12
|
public readonly rpcName: string
|
|
@@ -118,23 +117,51 @@ export class ContextAwareRPCService {
|
|
|
118
117
|
: undefined,
|
|
119
118
|
}
|
|
120
119
|
|
|
121
|
-
// Check
|
|
120
|
+
// Check addon namespace first (e.g. 'stripe:createCharge')
|
|
122
121
|
if (funcName.includes(':')) {
|
|
123
|
-
|
|
122
|
+
try {
|
|
123
|
+
return await this.invokeAddonFunction<In, Out>(
|
|
124
|
+
funcName,
|
|
125
|
+
data,
|
|
126
|
+
updatedWire
|
|
127
|
+
)
|
|
128
|
+
} catch (addonErr) {
|
|
129
|
+
if (!(addonErr instanceof RPCNotFoundError)) throw addonErr
|
|
130
|
+
// Not an addon — fall through to local lookup
|
|
131
|
+
}
|
|
124
132
|
}
|
|
125
133
|
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
// Try local function, then fall back to deployment service (remote)
|
|
135
|
+
try {
|
|
136
|
+
return await runPikkuFunc<In, Out>(
|
|
137
|
+
'rpc',
|
|
138
|
+
funcName,
|
|
139
|
+
getPikkuFunctionName(funcName),
|
|
140
|
+
{
|
|
141
|
+
auth: this.options.requiresAuth,
|
|
142
|
+
singletonServices: this.services,
|
|
143
|
+
data: () => data,
|
|
144
|
+
wire: updatedWire,
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
} catch (e) {
|
|
148
|
+
if (e instanceof RPCNotFoundError) {
|
|
149
|
+
// Fall back to deployment service (e.g. CF service binding, Lambda Invoke)
|
|
150
|
+
if (this.services.deploymentService) {
|
|
151
|
+
const session =
|
|
152
|
+
this.wire.getSession && typeof this.wire.getSession === 'function'
|
|
153
|
+
? await this.wire.getSession()
|
|
154
|
+
: (this.wire as any).session
|
|
155
|
+
return this.services.deploymentService.invoke(
|
|
156
|
+
funcName,
|
|
157
|
+
data,
|
|
158
|
+
session,
|
|
159
|
+
this.wire.traceId
|
|
160
|
+
) as Promise<Out>
|
|
161
|
+
}
|
|
136
162
|
}
|
|
137
|
-
|
|
163
|
+
throw e
|
|
164
|
+
}
|
|
138
165
|
}
|
|
139
166
|
|
|
140
167
|
/**
|
|
@@ -151,10 +178,7 @@ export class ContextAwareRPCService {
|
|
|
151
178
|
// Resolve namespace to package name
|
|
152
179
|
const resolved = resolveNamespace(namespacedFunction)
|
|
153
180
|
if (!resolved) {
|
|
154
|
-
throw new
|
|
155
|
-
`Unknown namespace in function reference: ${namespacedFunction}. ` +
|
|
156
|
-
`Make sure the package is registered in addons config.`
|
|
157
|
-
)
|
|
181
|
+
throw new RPCNotFoundError(namespacedFunction)
|
|
158
182
|
}
|
|
159
183
|
|
|
160
184
|
// Get the function meta from the addon package
|
|
@@ -162,10 +186,7 @@ export class ContextAwareRPCService {
|
|
|
162
186
|
const addonFunctionMeta = pikkuState(resolved.package, 'function', 'meta')
|
|
163
187
|
const funcMeta = addonFunctionMeta[resolved.function]
|
|
164
188
|
if (!funcMeta) {
|
|
165
|
-
throw new
|
|
166
|
-
`Function '${resolved.function}' not found in package '${resolved.package}'. ` +
|
|
167
|
-
`Available functions: ${Object.keys(addonFunctionMeta).join(', ') || '(none)'}`
|
|
168
|
-
)
|
|
189
|
+
throw new RPCNotFoundError(namespacedFunction)
|
|
169
190
|
}
|
|
170
191
|
const funcName = funcMeta.pikkuFuncId || resolved.function
|
|
171
192
|
|
|
@@ -210,17 +231,33 @@ export class ContextAwareRPCService {
|
|
|
210
231
|
return this.invokeAddonFunction<In, Out>(rpcName, data, mergedWire)
|
|
211
232
|
}
|
|
212
233
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
234
|
+
try {
|
|
235
|
+
return await runPikkuFunc<In, Out>(
|
|
236
|
+
'rpc',
|
|
237
|
+
rpcName,
|
|
238
|
+
getPikkuFunctionName(rpcName),
|
|
239
|
+
{
|
|
240
|
+
auth: this.options.requiresAuth,
|
|
241
|
+
singletonServices: this.services,
|
|
242
|
+
data: () => data,
|
|
243
|
+
wire: mergedWire,
|
|
244
|
+
}
|
|
245
|
+
)
|
|
246
|
+
} catch (e) {
|
|
247
|
+
if (e instanceof RPCNotFoundError && this.services.deploymentService) {
|
|
248
|
+
const session =
|
|
249
|
+
this.wire.getSession && typeof this.wire.getSession === 'function'
|
|
250
|
+
? await this.wire.getSession()
|
|
251
|
+
: (this.wire as any).session
|
|
252
|
+
return this.services.deploymentService.invoke(
|
|
253
|
+
rpcName,
|
|
254
|
+
data,
|
|
255
|
+
session,
|
|
256
|
+
this.wire.traceId
|
|
257
|
+
) as Promise<Out>
|
|
222
258
|
}
|
|
223
|
-
|
|
259
|
+
throw e
|
|
260
|
+
}
|
|
224
261
|
}
|
|
225
262
|
|
|
226
263
|
public async startWorkflow<In = any>(
|
|
@@ -332,94 +369,24 @@ export class ContextAwareRPCService {
|
|
|
332
369
|
funcName: string,
|
|
333
370
|
data: In
|
|
334
371
|
): Promise<Out> {
|
|
335
|
-
|
|
336
|
-
const headers: Record<string, string> = {
|
|
337
|
-
'Content-Type': 'application/json',
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const colonIndex = funcName.indexOf(':')
|
|
341
|
-
if (colonIndex !== -1) {
|
|
342
|
-
const namespace = funcName.substring(0, colonIndex)
|
|
343
|
-
const addons = pikkuState(null, 'addons', 'packages')
|
|
344
|
-
const pkgConfig = addons.get(namespace)
|
|
345
|
-
endpoint = pkgConfig?.rpcEndpoint
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (!endpoint && this.services.deploymentService) {
|
|
349
|
-
const deployments =
|
|
350
|
-
await this.services.deploymentService.findFunction(funcName)
|
|
351
|
-
if (deployments.length > 0) {
|
|
352
|
-
endpoint = deployments[0].endpoint
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
if (!endpoint) {
|
|
372
|
+
if (!this.services.deploymentService) {
|
|
357
373
|
throw new Error(
|
|
358
|
-
`No
|
|
359
|
-
`
|
|
360
|
-
)
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
let secret: string | undefined
|
|
364
|
-
if (this.services.secrets) {
|
|
365
|
-
try {
|
|
366
|
-
secret = await this.services.secrets.getSecret('PIKKU_REMOTE_SECRET')
|
|
367
|
-
} catch {}
|
|
368
|
-
}
|
|
369
|
-
if (secret) {
|
|
370
|
-
if (!this.services.jwt) {
|
|
371
|
-
throw new Error(
|
|
372
|
-
'PIKKU_REMOTE_SECRET is set but JWT service is not available'
|
|
373
|
-
)
|
|
374
|
-
}
|
|
375
|
-
const session =
|
|
376
|
-
this.wire.getSession && typeof this.wire.getSession === 'function'
|
|
377
|
-
? await this.wire.getSession()
|
|
378
|
-
: (this.wire as any).session
|
|
379
|
-
const sessionEnc = session
|
|
380
|
-
? await encryptJSON(secret, { session })
|
|
381
|
-
: undefined
|
|
382
|
-
const token = await this.services.jwt.encode(
|
|
383
|
-
{ value: 5, unit: 'minute' },
|
|
384
|
-
{
|
|
385
|
-
aud: 'pikku-remote',
|
|
386
|
-
fn: funcName,
|
|
387
|
-
iat: Date.now(),
|
|
388
|
-
session: sessionEnc,
|
|
389
|
-
}
|
|
374
|
+
`No DeploymentService configured for remote RPC: ${funcName}. ` +
|
|
375
|
+
`Set up a DeploymentService to enable remote function calls.`
|
|
390
376
|
)
|
|
391
|
-
headers.Authorization = `Bearer ${token}`
|
|
392
377
|
}
|
|
393
378
|
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
headers,
|
|
399
|
-
body: JSON.stringify({ data }),
|
|
400
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
401
|
-
})
|
|
402
|
-
|
|
403
|
-
if (!response.ok) {
|
|
404
|
-
let errorBody: string
|
|
405
|
-
try {
|
|
406
|
-
errorBody = JSON.stringify(await response.json())
|
|
407
|
-
} catch {
|
|
408
|
-
errorBody = await response.text()
|
|
409
|
-
}
|
|
410
|
-
throw new Error(
|
|
411
|
-
`Remote RPC call failed: ${response.status} ${response.statusText}. ${errorBody}`
|
|
412
|
-
)
|
|
413
|
-
}
|
|
379
|
+
const session =
|
|
380
|
+
this.wire.getSession && typeof this.wire.getSession === 'function'
|
|
381
|
+
? await this.wire.getSession()
|
|
382
|
+
: (this.wire as any).session
|
|
414
383
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
)
|
|
422
|
-
}
|
|
384
|
+
return this.services.deploymentService.invoke(
|
|
385
|
+
funcName,
|
|
386
|
+
data,
|
|
387
|
+
session,
|
|
388
|
+
this.wire.traceId
|
|
389
|
+
) as Promise<Out>
|
|
423
390
|
}
|
|
424
391
|
}
|
|
425
392
|
|
|
@@ -50,7 +50,7 @@ describe('wireScheduler', () => {
|
|
|
50
50
|
assert.equal(tasks.get('test-task'), mockTask)
|
|
51
51
|
})
|
|
52
52
|
|
|
53
|
-
test('should
|
|
53
|
+
test('should skip when scheduled task metadata not found', () => {
|
|
54
54
|
const mockTask: CoreScheduledTask = {
|
|
55
55
|
name: 'missing-meta-task',
|
|
56
56
|
schedule: '0 0 * * *',
|
|
@@ -60,16 +60,10 @@ describe('wireScheduler', () => {
|
|
|
60
60
|
},
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
error.message,
|
|
68
|
-
"Missing generated metadata for scheduled task 'missing-meta-task'"
|
|
69
|
-
)
|
|
70
|
-
return true
|
|
71
|
-
}
|
|
72
|
-
)
|
|
63
|
+
wireScheduler(mockTask)
|
|
64
|
+
|
|
65
|
+
const tasks = pikkuState(null, 'scheduler', 'tasks')
|
|
66
|
+
assert.equal(tasks.has('missing-meta-task'), false)
|
|
73
67
|
})
|
|
74
68
|
|
|
75
69
|
test('should throw error when scheduled task already exists', () => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { PikkuWire, CoreUserSession } from '../../types/core.types.js'
|
|
2
2
|
import type { CoreScheduledTask } from './scheduler.types.js'
|
|
3
3
|
import { getErrorResponse, PikkuError } from '../../errors/error-handler.js'
|
|
4
|
-
import { PikkuMissingMetaError } from '../../errors/errors.js'
|
|
5
4
|
import {
|
|
6
5
|
getSingletonServices,
|
|
7
6
|
getCreateWireServices,
|
|
@@ -20,6 +19,8 @@ import type {
|
|
|
20
19
|
export type RunScheduledTasksParams = {
|
|
21
20
|
name: string
|
|
22
21
|
session?: CoreUserSession
|
|
22
|
+
/** Pre-resolved trace ID */
|
|
23
|
+
traceId?: string
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export const wireScheduler = <
|
|
@@ -32,9 +33,10 @@ export const wireScheduler = <
|
|
|
32
33
|
const meta = pikkuState(null, 'scheduler', 'meta')
|
|
33
34
|
const taskMeta = meta[scheduledTask.name]
|
|
34
35
|
if (!taskMeta) {
|
|
35
|
-
|
|
36
|
-
`
|
|
36
|
+
console.warn(
|
|
37
|
+
`[pikku] Skipping scheduled task '${scheduledTask.name}' — metadata not found. Consider moving this wiring to its own file.`
|
|
37
38
|
)
|
|
39
|
+
return
|
|
38
40
|
}
|
|
39
41
|
addFunction(taskMeta.pikkuFuncId, {
|
|
40
42
|
func: scheduledTask.func.func,
|
|
@@ -69,9 +71,14 @@ class ScheduledTaskSkippedError extends PikkuError {
|
|
|
69
71
|
export async function runScheduledTask({
|
|
70
72
|
name,
|
|
71
73
|
session,
|
|
74
|
+
traceId,
|
|
72
75
|
}: RunScheduledTasksParams): Promise<void> {
|
|
73
76
|
const singletonServices = getSingletonServices()
|
|
74
77
|
const createWireServices = getCreateWireServices()
|
|
78
|
+
const resolvedTraceId = traceId ?? `cron-${name}-${Date.now()}`
|
|
79
|
+
const scopedLogger =
|
|
80
|
+
singletonServices.logger.scope?.(resolvedTraceId) ??
|
|
81
|
+
singletonServices.logger
|
|
75
82
|
const task = pikkuState(null, 'scheduler', 'tasks').get(name)
|
|
76
83
|
const meta = pikkuState(null, 'scheduler', 'meta')[name]
|
|
77
84
|
|
|
@@ -91,6 +98,7 @@ export async function runScheduledTask({
|
|
|
91
98
|
|
|
92
99
|
// Create the scheduled task wire object
|
|
93
100
|
const wire: PikkuWire = {
|
|
101
|
+
traceId: resolvedTraceId,
|
|
94
102
|
scheduledTask: {
|
|
95
103
|
name,
|
|
96
104
|
schedule: task.schedule,
|
|
@@ -103,7 +111,7 @@ export async function runScheduledTask({
|
|
|
103
111
|
}
|
|
104
112
|
|
|
105
113
|
try {
|
|
106
|
-
|
|
114
|
+
scopedLogger.info(
|
|
107
115
|
`Running schedule task: ${name} | schedule: ${task.schedule}`
|
|
108
116
|
)
|
|
109
117
|
|
|
@@ -122,7 +130,7 @@ export async function runScheduledTask({
|
|
|
122
130
|
} catch (e: any) {
|
|
123
131
|
const errorResponse = getErrorResponse(e)
|
|
124
132
|
if (errorResponse != null) {
|
|
125
|
-
|
|
133
|
+
scopedLogger.error(e)
|
|
126
134
|
}
|
|
127
135
|
throw e
|
|
128
136
|
}
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
getTriggerMeta,
|
|
8
8
|
} from './trigger-runner.js'
|
|
9
9
|
import { resetPikkuState, pikkuState } from '../../pikku-state.js'
|
|
10
|
-
import { PikkuMissingMetaError } from '../../errors/errors.js'
|
|
11
10
|
|
|
12
11
|
beforeEach(() => {
|
|
13
12
|
resetPikkuState()
|
|
@@ -24,11 +23,11 @@ describe('wireTrigger', () => {
|
|
|
24
23
|
assert.ok(triggers.has('myTrigger'))
|
|
25
24
|
})
|
|
26
25
|
|
|
27
|
-
test('should
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
26
|
+
test('should skip when trigger metadata not found', () => {
|
|
27
|
+
wireTrigger({ name: 'noMeta', func: async () => {} } as any)
|
|
28
|
+
|
|
29
|
+
const triggers = getRegisteredTriggers()
|
|
30
|
+
assert.ok(!triggers.has('noMeta'))
|
|
32
31
|
})
|
|
33
32
|
})
|
|
34
33
|
|
|
@@ -43,11 +42,11 @@ describe('wireTriggerSource', () => {
|
|
|
43
42
|
assert.ok(sources.has('mySource'))
|
|
44
43
|
})
|
|
45
44
|
|
|
46
|
-
test('should
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
45
|
+
test('should skip when trigger source metadata not found', () => {
|
|
46
|
+
wireTriggerSource({ name: 'noMeta', func: async () => {} } as any)
|
|
47
|
+
|
|
48
|
+
const sources = pikkuState(null, 'trigger', 'triggerSources')
|
|
49
|
+
assert.ok(!sources.has('noMeta'))
|
|
51
50
|
})
|
|
52
51
|
|
|
53
52
|
test('should throw when trigger source already exists', () => {
|
|
@@ -21,9 +21,10 @@ export const wireTrigger = (trigger: CoreTrigger) => {
|
|
|
21
21
|
const meta = pikkuState(null, 'trigger', 'meta')
|
|
22
22
|
const triggerMeta = meta[trigger.name]
|
|
23
23
|
if (!triggerMeta) {
|
|
24
|
-
|
|
25
|
-
`
|
|
24
|
+
console.warn(
|
|
25
|
+
`[pikku] Skipping trigger '${trigger.name}' — metadata not found. Consider moving this wiring to its own file.`
|
|
26
26
|
)
|
|
27
|
+
return
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
addFunction(triggerMeta.pikkuFuncId, trigger.func as any)
|
|
@@ -43,9 +44,10 @@ export const wireTriggerSource = <TInput = unknown, TOutput = unknown>(
|
|
|
43
44
|
const sourceMeta = pikkuState(null, 'trigger', 'sourceMeta')
|
|
44
45
|
const triggerSourceMeta = sourceMeta[source.name]
|
|
45
46
|
if (!triggerSourceMeta) {
|
|
46
|
-
|
|
47
|
-
`
|
|
47
|
+
console.warn(
|
|
48
|
+
`[pikku] Skipping trigger source '${source.name}' — metadata not found. Consider moving this wiring to its own file.`
|
|
48
49
|
)
|
|
50
|
+
return
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
const triggerSources = pikkuState(null, 'trigger', 'triggerSources')
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
import { pikkuState } from '../../../pikku-state.js'
|
|
2
2
|
import { addFunction } from '../../../function/function-runner.js'
|
|
3
|
-
import { PikkuMissingMetaError } from '../../../errors/errors.js'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Add a workflow to the system
|
|
7
6
|
* This is called by the generated workflow wirings
|
|
8
7
|
*/
|
|
9
|
-
export const addWorkflow = (
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
export const addWorkflow = (
|
|
9
|
+
workflowName: string,
|
|
10
|
+
workflowFunc: any,
|
|
11
|
+
packageName: string | null = null
|
|
12
|
+
) => {
|
|
13
|
+
const meta = pikkuState(packageName, 'workflows', 'meta')
|
|
12
14
|
const workflowMeta = meta[workflowName]
|
|
13
15
|
if (!workflowMeta) {
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
+
console.warn(
|
|
17
|
+
`[pikku] Skipping workflow '${workflowName}' — metadata not found. Consider moving this wiring to its own file.`
|
|
16
18
|
)
|
|
19
|
+
return
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
const registrations = pikkuState(null, 'workflows', 'registrations')
|
|
22
|
+
const registrations = pikkuState(packageName, 'workflows', 'registrations')
|
|
21
23
|
registrations.set(workflowName, {
|
|
22
24
|
name: workflowName,
|
|
23
25
|
func: workflowFunc,
|
|
24
26
|
})
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
addFunction(workflowMeta.pikkuFuncId, workflowFunc)
|
|
28
|
+
addFunction(workflowMeta.pikkuFuncId, workflowFunc, packageName)
|
|
28
29
|
}
|
|
@@ -116,8 +116,22 @@ function isTemplate(value: unknown): value is TemplateValue {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
function getWorkflowMeta(name: string): WorkflowRuntimeMeta | undefined {
|
|
119
|
-
const
|
|
120
|
-
return
|
|
119
|
+
const rootMeta = pikkuState(null, 'workflows', 'meta')
|
|
120
|
+
if (rootMeta[name]) return rootMeta[name]
|
|
121
|
+
|
|
122
|
+
const colonIndex = name.indexOf(':')
|
|
123
|
+
if (colonIndex !== -1) {
|
|
124
|
+
const namespace = name.substring(0, colonIndex)
|
|
125
|
+
const localName = name.substring(colonIndex + 1)
|
|
126
|
+
const addons = pikkuState(null, 'addons', 'packages')
|
|
127
|
+
const pkgConfig = addons?.get(namespace)
|
|
128
|
+
if (pkgConfig) {
|
|
129
|
+
const addonMeta = pikkuState(pkgConfig.package, 'workflows', 'meta')
|
|
130
|
+
if (addonMeta?.[localName]) return addonMeta[localName]
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return undefined
|
|
121
135
|
}
|
|
122
136
|
|
|
123
137
|
function resolveNextFromConfig(next: unknown, branchKey?: string): string[] {
|
|
@@ -798,9 +812,10 @@ export async function runWorkflowGraph(
|
|
|
798
812
|
rpcService?: any,
|
|
799
813
|
inline?: boolean,
|
|
800
814
|
startNode?: string,
|
|
801
|
-
wire?: WorkflowRunWire
|
|
815
|
+
wire?: WorkflowRunWire,
|
|
816
|
+
overrideMeta?: WorkflowRuntimeMeta
|
|
802
817
|
): Promise<{ runId: string }> {
|
|
803
|
-
const meta = getWorkflowMeta(graphName)
|
|
818
|
+
const meta = overrideMeta ?? getWorkflowMeta(graphName)
|
|
804
819
|
if (!meta?.nodes) {
|
|
805
820
|
throw new Error(`Workflow graph '${graphName}' not found`)
|
|
806
821
|
}
|
|
@@ -20,13 +20,23 @@ export {
|
|
|
20
20
|
type PikkuWorkflowGraphResult,
|
|
21
21
|
} from './graph/wire-workflow-graph.js'
|
|
22
22
|
|
|
23
|
-
//
|
|
23
|
+
// Graph validation and dynamic workflow utilities
|
|
24
24
|
export {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
validateWorkflowWiring,
|
|
26
|
+
computeEntryNodeIds,
|
|
27
|
+
} from './graph/graph-validation.js'
|
|
28
|
+
|
|
29
|
+
// Queue worker functions (registered by codegen, executed at runtime)
|
|
30
|
+
export {
|
|
31
|
+
pikkuWorkflowWorkerFunc,
|
|
32
|
+
pikkuWorkflowOrchestratorFunc,
|
|
33
|
+
pikkuWorkflowSleeperFunc,
|
|
34
|
+
} from './workflow-queue-workers.js'
|
|
35
|
+
export type {
|
|
36
|
+
WorkflowStepInput as WorkflowStepQueueInput,
|
|
37
|
+
PikkuWorkflowOrchestratorInput,
|
|
38
|
+
PikkuWorkflowSleeperInput,
|
|
39
|
+
} from './workflow-queue-workers.js'
|
|
30
40
|
|
|
31
41
|
// Re-export all types from workflow.types
|
|
32
42
|
export type {
|
|
@@ -37,6 +47,7 @@ export type {
|
|
|
37
47
|
WorkflowVersionStatus,
|
|
38
48
|
StepStatus,
|
|
39
49
|
WorkflowRun,
|
|
50
|
+
WorkflowRunStatus,
|
|
40
51
|
StepState,
|
|
41
52
|
WorkflowRunService,
|
|
42
53
|
CoreWorkflow,
|