@pikku/core 0.12.39 → 0.12.41
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 +29 -0
- package/dist/function/function-runner.d.ts +2 -2
- package/dist/function/functions.types.d.ts +6 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/services/credential-wire-service.d.ts +2 -2
- package/dist/services/in-memory-workflow-service.d.ts +1 -0
- package/dist/services/in-memory-workflow-service.js +3 -0
- package/dist/services/pikku-user-id.d.ts +2 -2
- package/dist/services/workflow-service.d.ts +1 -0
- package/dist/types/core.types.d.ts +24 -7
- package/dist/utils.d.ts +3 -1
- package/dist/utils.js +2 -0
- package/dist/wirings/channel/channel-middleware-runner.d.ts +2 -2
- package/dist/wirings/channel/local/local-eventhub-service.js +7 -4
- package/dist/wirings/rpc/rpc-runner.d.ts +4 -4
- package/dist/wirings/rpc/rpc-runner.js +0 -16
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +5 -2
- package/dist/wirings/workflow/pikku-workflow-service.js +17 -17
- package/package.json +1 -1
- package/src/function/function-runner.ts +3 -2
- package/src/function/functions.types.ts +6 -2
- package/src/index.ts +7 -1
- package/src/services/credential-wire-service.ts +2 -2
- package/src/services/in-memory-workflow-service.test.ts +2 -2
- package/src/services/in-memory-workflow-service.ts +7 -1
- package/src/services/pikku-user-id.ts +2 -2
- package/src/services/workflow-service.ts +1 -0
- package/src/types/core.types.ts +28 -8
- package/src/utils.ts +12 -1
- package/src/wirings/ai-agent/ai-agent-prepare.ts +2 -2
- package/src/wirings/channel/channel-common.ts +8 -2
- package/src/wirings/channel/channel-middleware-runner.ts +3 -3
- package/src/wirings/channel/local/local-channel-runner.ts +7 -3
- package/src/wirings/channel/local/local-eventhub-service.ts +6 -3
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +4 -4
- package/src/wirings/cli/cli-runner.ts +2 -2
- package/src/wirings/gateway/gateway-runner.ts +8 -2
- package/src/wirings/http/http-runner.ts +3 -2
- package/src/wirings/mcp/mcp-runner.ts +2 -2
- package/src/wirings/queue/queue-runner.ts +2 -2
- package/src/wirings/rpc/rpc-runner.ts +12 -24
- package/src/wirings/scheduler/scheduler-runner.ts +2 -2
- package/src/wirings/trigger/trigger-runner.ts +2 -2
- package/src/wirings/workflow/pikku-workflow-service.test.ts +16 -26
- package/src/wirings/workflow/pikku-workflow-service.ts +36 -24
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +3 -3
- package/tsconfig.tsbuildinfo +1 -1
package/src/types/core.types.ts
CHANGED
|
@@ -119,8 +119,12 @@ export type FunctionRuntimeMeta = {
|
|
|
119
119
|
readonly?: boolean
|
|
120
120
|
deploy?: 'serverless' | 'server' | 'auto'
|
|
121
121
|
sessionless?: boolean
|
|
122
|
-
/** When
|
|
123
|
-
|
|
122
|
+
/** When true, workflow steps calling this function are dispatched via the queue. No queue service configured is a hard error. */
|
|
123
|
+
workflowQueued?: boolean
|
|
124
|
+
/** Retry count when this function is used as a workflow step. */
|
|
125
|
+
workflowRetries?: number
|
|
126
|
+
/** Timeout when this function is used as a workflow step (e.g. '30s', '5m'). */
|
|
127
|
+
workflowTimeout?: string
|
|
124
128
|
version?: number
|
|
125
129
|
approvalRequired?: boolean
|
|
126
130
|
approvalDescription?: string
|
|
@@ -174,8 +178,7 @@ export type JSONValue =
|
|
|
174
178
|
/**
|
|
175
179
|
* Utility type for making certain keys required and leaving the rest as optional.
|
|
176
180
|
*/
|
|
177
|
-
export type PickRequired<T, K extends keyof T> = Required<Pick<T, K>>
|
|
178
|
-
Partial<T>
|
|
181
|
+
export type PickRequired<T, K extends keyof T> = T & Required<Pick<T, K>>
|
|
179
182
|
|
|
180
183
|
/**
|
|
181
184
|
* Utility type for making certain keys optional while keeping the rest required.
|
|
@@ -281,7 +284,10 @@ export type PikkuWire<
|
|
|
281
284
|
MCPTools extends string | never = never,
|
|
282
285
|
TypedWorkflow extends PikkuWorkflowWire | never = PikkuWorkflowWire,
|
|
283
286
|
TriggerOutput = unknown,
|
|
284
|
-
> =
|
|
287
|
+
> = {
|
|
288
|
+
/** Always present — lazily initialised on first access for every function invocation */
|
|
289
|
+
rpc: TypedRPC
|
|
290
|
+
} & Partial<{
|
|
285
291
|
wireType: PikkuWiringTypes
|
|
286
292
|
wireId: string
|
|
287
293
|
/** Trace ID for distributed tracing — propagated across remote RPC calls via x-trace-id header */
|
|
@@ -290,7 +296,6 @@ export type PikkuWire<
|
|
|
290
296
|
functionId: string
|
|
291
297
|
http: PikkuHTTP<In>
|
|
292
298
|
mcp: PikkuMCP<MCPTools>
|
|
293
|
-
rpc: TypedRPC
|
|
294
299
|
channel: [IsChannel] extends [null]
|
|
295
300
|
? PikkuChannel<unknown, Out>
|
|
296
301
|
: PikkuChannel<unknown, Out> | undefined
|
|
@@ -329,6 +334,11 @@ export type PikkuWire<
|
|
|
329
334
|
}
|
|
330
335
|
}>
|
|
331
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Wire object as constructed by runners, before rpc is lazily added by the function runner.
|
|
339
|
+
*/
|
|
340
|
+
export type PikkuRawWire = Omit<PikkuWire, 'rpc'>
|
|
341
|
+
|
|
332
342
|
/**
|
|
333
343
|
* A function that can wrap an wire and be called before or after
|
|
334
344
|
*/
|
|
@@ -337,7 +347,7 @@ export type CorePikkuMiddleware<
|
|
|
337
347
|
UserSession extends CoreUserSession = CoreUserSession,
|
|
338
348
|
> = (
|
|
339
349
|
services: SingletonServices,
|
|
340
|
-
wires: PikkuWire
|
|
350
|
+
wires: PikkuWire,
|
|
341
351
|
next: () => Promise<void>
|
|
342
352
|
) => Promise<void>
|
|
343
353
|
|
|
@@ -523,7 +533,7 @@ export type CreateWireServices<
|
|
|
523
533
|
UserSession extends CoreUserSession = CoreUserSession,
|
|
524
534
|
> = (
|
|
525
535
|
services: SingletonServices,
|
|
526
|
-
wire:
|
|
536
|
+
wire: PikkuRawWire
|
|
527
537
|
) => Promise<WireServices<Services, SingletonServices>>
|
|
528
538
|
|
|
529
539
|
/**
|
|
@@ -534,6 +544,16 @@ export type CreateConfig<
|
|
|
534
544
|
RemainingArgs extends any[] = unknown[],
|
|
535
545
|
> = (variables?: VariablesService, ...args: RemainingArgs) => Promise<Config>
|
|
536
546
|
|
|
547
|
+
/** Server lifecycle hooks for startup and shutdown phases. */
|
|
548
|
+
export type ServerLifecycle<
|
|
549
|
+
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
550
|
+
> = {
|
|
551
|
+
beforeStart?: (services: SingletonServices) => void | Promise<void>
|
|
552
|
+
afterStart?: (services: SingletonServices) => void | Promise<void>
|
|
553
|
+
beforeStop?: (services: SingletonServices) => void | Promise<void>
|
|
554
|
+
afterStop?: (services: SingletonServices) => void | Promise<void>
|
|
555
|
+
}
|
|
556
|
+
|
|
537
557
|
/**
|
|
538
558
|
* Represents the documentation for a route, including summary, description, tags, and errors.
|
|
539
559
|
*/
|
package/src/utils.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Logger } from './services/logger.js'
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
CoreSingletonServices,
|
|
4
|
+
ServerLifecycle,
|
|
5
|
+
WireServices,
|
|
6
|
+
} from './types/core.types.js'
|
|
3
7
|
import { getSingletonServices, getAllPackageStates } from './pikku-state.js'
|
|
4
8
|
|
|
5
9
|
export const closeWireServices = async (
|
|
@@ -127,3 +131,10 @@ export const stopSingletonServices = async (): Promise<void> => {
|
|
|
127
131
|
await stopService(logger, name, service)
|
|
128
132
|
}
|
|
129
133
|
}
|
|
134
|
+
|
|
135
|
+
/** Wrap server lifecycle hooks so the inspector can discover them. */
|
|
136
|
+
export const pikkuServerLifecycle = <
|
|
137
|
+
SS extends CoreSingletonServices = CoreSingletonServices,
|
|
138
|
+
>(
|
|
139
|
+
lifecycle: ServerLifecycle<SS>
|
|
140
|
+
): ServerLifecycle<SS> => lifecycle
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PikkuRawWire, CoreUserSession } from '../../types/core.types.js'
|
|
2
2
|
import type {
|
|
3
3
|
CoreAIAgent,
|
|
4
4
|
AIAgentInput,
|
|
@@ -397,7 +397,7 @@ export async function buildToolDefs(
|
|
|
397
397
|
needsApproval: needsApproval || undefined,
|
|
398
398
|
approvalDescriptionFn,
|
|
399
399
|
execute: async (toolInput: unknown) => {
|
|
400
|
-
const wire:
|
|
400
|
+
const wire: PikkuRawWire = params.sessionService
|
|
401
401
|
? { ...createMiddlewareSessionWireProps(params.sessionService) }
|
|
402
402
|
: {}
|
|
403
403
|
const rpcService = new ContextAwareRPCService(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CoreSingletonServices,
|
|
3
3
|
CorePikkuMiddleware,
|
|
4
|
+
PikkuRawWire,
|
|
4
5
|
PikkuWire,
|
|
5
6
|
MiddlewareMetadata,
|
|
6
7
|
} from '../../types/core.types.js'
|
|
@@ -73,7 +74,7 @@ export const runChannelLifecycleWithMiddleware = async ({
|
|
|
73
74
|
}
|
|
74
75
|
)
|
|
75
76
|
|
|
76
|
-
let wire:
|
|
77
|
+
let wire: PikkuRawWire = { channel }
|
|
77
78
|
if (allChannelMiddleware.length > 0) {
|
|
78
79
|
wire = wrapChannelWithMiddleware(wire, services, allChannelMiddleware)
|
|
79
80
|
}
|
|
@@ -90,7 +91,12 @@ export const runChannelLifecycleWithMiddleware = async ({
|
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
if (allMiddleware.length > 0) {
|
|
93
|
-
return await runMiddleware(
|
|
94
|
+
return await runMiddleware(
|
|
95
|
+
services,
|
|
96
|
+
wire as unknown as PikkuWire,
|
|
97
|
+
allMiddleware,
|
|
98
|
+
runLifecycle
|
|
99
|
+
)
|
|
94
100
|
} else {
|
|
95
101
|
return await runLifecycle()
|
|
96
102
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CoreSingletonServices,
|
|
3
3
|
MiddlewareMetadata,
|
|
4
|
-
|
|
4
|
+
PikkuRawWire,
|
|
5
5
|
} from '../../types/core.types.js'
|
|
6
6
|
import type { CorePikkuChannelMiddleware } from './channel.types.js'
|
|
7
7
|
import { pikkuState } from '../../pikku-state.js'
|
|
@@ -87,10 +87,10 @@ export const combineChannelMiddleware = (
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
export function wrapChannelWithMiddleware<Out>(
|
|
90
|
-
wire:
|
|
90
|
+
wire: PikkuRawWire,
|
|
91
91
|
services: CoreSingletonServices,
|
|
92
92
|
middlewares: readonly CorePikkuChannelMiddleware[]
|
|
93
|
-
):
|
|
93
|
+
): PikkuRawWire {
|
|
94
94
|
if (middlewares.length === 0 || !wire.channel) return wire
|
|
95
95
|
|
|
96
96
|
const channel = wire.channel
|
|
@@ -4,7 +4,11 @@ import { closeWireServices } from '../../../utils.js'
|
|
|
4
4
|
import { processMessageHandlers } from '../channel-handler.js'
|
|
5
5
|
import type { CoreChannel, RunChannelOptions } from '../channel.types.js'
|
|
6
6
|
import { PikkuLocalChannelHandler } from './local-channel-handler.js'
|
|
7
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
PikkuRawWire,
|
|
9
|
+
PikkuWire,
|
|
10
|
+
WireServices,
|
|
11
|
+
} from '../../../types/core.types.js'
|
|
8
12
|
import { isProduction } from '../../../env.js'
|
|
9
13
|
import { getErrorResponse } from '../../../errors/error-handler.js'
|
|
10
14
|
import { handleHTTPError } from '../../../handle-error.js'
|
|
@@ -46,7 +50,7 @@ const runUpgradeMiddleware = async (
|
|
|
46
50
|
{
|
|
47
51
|
http,
|
|
48
52
|
...createMiddlewareSessionWireProps(userSession),
|
|
49
|
-
},
|
|
53
|
+
} as unknown as PikkuWire,
|
|
50
54
|
middleware
|
|
51
55
|
)
|
|
52
56
|
}
|
|
@@ -123,7 +127,7 @@ export const runLocalChannel = async ({
|
|
|
123
127
|
singletonServices.logger
|
|
124
128
|
)
|
|
125
129
|
const channel = channelHandler.getChannel()
|
|
126
|
-
const wire:
|
|
130
|
+
const wire: PikkuRawWire = {
|
|
127
131
|
channel,
|
|
128
132
|
...createMiddlewareSessionWireProps(userSession),
|
|
129
133
|
}
|
|
@@ -69,9 +69,12 @@ export class LocalEventHubService<
|
|
|
69
69
|
if (channelId === toChannelId) continue // Skip sending to the sender
|
|
70
70
|
const channel = this.channels.get(toChannelId)
|
|
71
71
|
if (channel) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
try {
|
|
73
|
+
channel.send(data, isBinary)
|
|
74
|
+
} catch {
|
|
75
|
+
// Channel closed (e.g. SSE ReadableStream controller already closed on browser disconnect) — clean up
|
|
76
|
+
this.onChannelClosed(toChannelId)
|
|
77
|
+
}
|
|
75
78
|
}
|
|
76
79
|
}
|
|
77
80
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CoreUserSession,
|
|
3
|
-
|
|
3
|
+
PikkuRawWire,
|
|
4
4
|
WireServices,
|
|
5
5
|
} from '../../../types/core.types.js'
|
|
6
6
|
import { closeWireServices } from '../../../utils.js'
|
|
@@ -120,7 +120,7 @@ export const runChannelConnect = async ({
|
|
|
120
120
|
channel.getState = () => channelStore.getState(channelId) as any
|
|
121
121
|
channel.clearState = () => channelStore.clearState(channelId)
|
|
122
122
|
|
|
123
|
-
const wire:
|
|
123
|
+
const wire: PikkuRawWire = {
|
|
124
124
|
channel,
|
|
125
125
|
...createMiddlewareSessionWireProps(userSession),
|
|
126
126
|
}
|
|
@@ -216,7 +216,7 @@ export const runChannelDisconnect = async ({
|
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
const wire:
|
|
219
|
+
const wire: PikkuRawWire = {
|
|
220
220
|
channel,
|
|
221
221
|
...createMiddlewareSessionWireProps(userSession),
|
|
222
222
|
}
|
|
@@ -288,7 +288,7 @@ export const runChannelMessage = async (
|
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
const wire:
|
|
291
|
+
const wire: PikkuRawWire = {
|
|
292
292
|
channel,
|
|
293
293
|
...createMiddlewareSessionWireProps(userSession),
|
|
294
294
|
}
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
CoreSingletonServices,
|
|
20
20
|
CoreServices,
|
|
21
21
|
CreateWireServices,
|
|
22
|
-
|
|
22
|
+
PikkuRawWire,
|
|
23
23
|
CreateConfig,
|
|
24
24
|
CreateSingletonServices,
|
|
25
25
|
} from '../../types/core.types.js'
|
|
@@ -356,7 +356,7 @@ export async function runCLICommand({
|
|
|
356
356
|
singletonServices.sessionStore
|
|
357
357
|
)
|
|
358
358
|
|
|
359
|
-
const wire:
|
|
359
|
+
const wire: PikkuRawWire = {
|
|
360
360
|
cli: {
|
|
361
361
|
program,
|
|
362
362
|
command: commandPath,
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
} from './gateway.types.js'
|
|
11
11
|
import type {
|
|
12
12
|
PikkuWire,
|
|
13
|
+
PikkuRawWire,
|
|
13
14
|
CorePikkuMiddleware,
|
|
14
15
|
CoreSingletonServices,
|
|
15
16
|
} from '../../types/core.types.js'
|
|
@@ -381,7 +382,7 @@ export const createListenerMessageHandler = (
|
|
|
381
382
|
const parsed = adapter.parse(rawData)
|
|
382
383
|
if (!parsed) return
|
|
383
384
|
|
|
384
|
-
const wire:
|
|
385
|
+
const wire: PikkuRawWire = {}
|
|
385
386
|
const gateway: PikkuGateway = {
|
|
386
387
|
gatewayName: name,
|
|
387
388
|
senderId: parsed.senderId,
|
|
@@ -403,7 +404,12 @@ export const createListenerMessageHandler = (
|
|
|
403
404
|
}
|
|
404
405
|
|
|
405
406
|
if (allMiddleware.length > 0) {
|
|
406
|
-
await runMiddleware(
|
|
407
|
+
await runMiddleware(
|
|
408
|
+
singletonServices,
|
|
409
|
+
wire as unknown as PikkuWire,
|
|
410
|
+
allMiddleware,
|
|
411
|
+
exec
|
|
412
|
+
)
|
|
407
413
|
} else {
|
|
408
414
|
await exec()
|
|
409
415
|
}
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
CorePikkuMiddleware,
|
|
19
19
|
CorePikkuMiddlewareGroup,
|
|
20
20
|
WireServices,
|
|
21
|
+
PikkuRawWire,
|
|
21
22
|
PikkuWire,
|
|
22
23
|
PikkuWiringTypes,
|
|
23
24
|
} from '../../types/core.types.js'
|
|
@@ -408,7 +409,7 @@ const executeRoute = async (
|
|
|
408
409
|
}
|
|
409
410
|
}
|
|
410
411
|
|
|
411
|
-
const wire:
|
|
412
|
+
const wire: PikkuRawWire = {
|
|
412
413
|
traceId: requestId,
|
|
413
414
|
http,
|
|
414
415
|
channel,
|
|
@@ -586,7 +587,7 @@ export const fetchData = async <In, Out>(
|
|
|
586
587
|
if (apiType.toLowerCase() === 'options') {
|
|
587
588
|
const httpGroups = pikkuState(null, 'middleware', 'httpGroup')
|
|
588
589
|
const globalMiddleware = httpGroups['*']
|
|
589
|
-
const wire
|
|
590
|
+
const wire = { http: http! } as unknown as PikkuWire
|
|
590
591
|
if (globalMiddleware) {
|
|
591
592
|
await runMiddleware(
|
|
592
593
|
singletonServices,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PikkuRawWire } from '../../types/core.types.js'
|
|
2
2
|
import type {
|
|
3
3
|
CoreMCPResource,
|
|
4
4
|
CoreMCPPrompt,
|
|
@@ -217,7 +217,7 @@ async function runMCPPikkuFunc(
|
|
|
217
217
|
const mcpSessionService = new PikkuSessionService(
|
|
218
218
|
singletonServices.sessionStore
|
|
219
219
|
)
|
|
220
|
-
const wire:
|
|
220
|
+
const wire: PikkuRawWire = {
|
|
221
221
|
mcp: mcpWire,
|
|
222
222
|
...createMiddlewareSessionWireProps(mcpSessionService),
|
|
223
223
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PikkuRawWire } from '../../types/core.types.js'
|
|
2
2
|
import type { CoreQueueWorker, QueueJob, PikkuQueue } from './queue.types.js'
|
|
3
3
|
import type {
|
|
4
4
|
CorePikkuFunctionConfig,
|
|
@@ -156,7 +156,7 @@ export async function runQueueJob({
|
|
|
156
156
|
try {
|
|
157
157
|
logger.info(`Processing job ${job.id} in queue ${job.queueName}`)
|
|
158
158
|
|
|
159
|
-
const wire:
|
|
159
|
+
const wire: PikkuRawWire = {
|
|
160
160
|
traceId: resolvedTraceId,
|
|
161
161
|
queue,
|
|
162
162
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
CoreServices,
|
|
3
|
+
PikkuWire,
|
|
4
|
+
PikkuRawWire,
|
|
5
|
+
} from '../../types/core.types.js'
|
|
2
6
|
import type { SessionService } from '../../services/user-session-service.js'
|
|
3
7
|
import type { CoreUserSession } from '../../types/core.types.js'
|
|
4
8
|
import { runPikkuFunc } from '../../function/function-runner.js'
|
|
@@ -100,7 +104,7 @@ const resolvePikkuFunction = (
|
|
|
100
104
|
export class ContextAwareRPCService {
|
|
101
105
|
constructor(
|
|
102
106
|
private services: CoreServices,
|
|
103
|
-
private wire:
|
|
107
|
+
private wire: PikkuRawWire,
|
|
104
108
|
private options: {
|
|
105
109
|
requiresAuth?: boolean
|
|
106
110
|
sessionService?: SessionService<CoreUserSession>
|
|
@@ -136,16 +140,8 @@ export class ContextAwareRPCService {
|
|
|
136
140
|
funcName: string,
|
|
137
141
|
data: In
|
|
138
142
|
): Promise<Out> {
|
|
139
|
-
const
|
|
140
|
-
const updatedWire: PikkuWire = {
|
|
143
|
+
const updatedWire: PikkuRawWire = {
|
|
141
144
|
...this.wire,
|
|
142
|
-
rpc: this.wire.rpc
|
|
143
|
-
? {
|
|
144
|
-
...this.wire.rpc,
|
|
145
|
-
depth: rpcDepth + 1,
|
|
146
|
-
global: false,
|
|
147
|
-
}
|
|
148
|
-
: undefined,
|
|
149
145
|
}
|
|
150
146
|
|
|
151
147
|
// Check addon namespace first (e.g. 'stripe:createCharge')
|
|
@@ -209,7 +205,7 @@ export class ContextAwareRPCService {
|
|
|
209
205
|
private async invokeAddonFunction<In = any, Out = any>(
|
|
210
206
|
namespacedFunction: string,
|
|
211
207
|
data: In,
|
|
212
|
-
wire:
|
|
208
|
+
wire: PikkuRawWire
|
|
213
209
|
): Promise<Out> {
|
|
214
210
|
// Resolve namespace to package name
|
|
215
211
|
const resolved = resolveNamespace(namespacedFunction)
|
|
@@ -248,19 +244,11 @@ export class ContextAwareRPCService {
|
|
|
248
244
|
public async rpcWithWire<In = any, Out = any>(
|
|
249
245
|
rpcName: string,
|
|
250
246
|
data: In,
|
|
251
|
-
wire:
|
|
247
|
+
wire: PikkuRawWire
|
|
252
248
|
): Promise<Out> {
|
|
253
|
-
const
|
|
254
|
-
const mergedWire: PikkuWire = {
|
|
249
|
+
const mergedWire: PikkuRawWire = {
|
|
255
250
|
...this.wire,
|
|
256
251
|
...wire,
|
|
257
|
-
rpc: this.wire.rpc
|
|
258
|
-
? {
|
|
259
|
-
...this.wire.rpc,
|
|
260
|
-
depth: rpcDepth + 1,
|
|
261
|
-
global: false,
|
|
262
|
-
}
|
|
263
|
-
: undefined,
|
|
264
252
|
}
|
|
265
253
|
|
|
266
254
|
if (rpcName.includes(':')) {
|
|
@@ -438,7 +426,7 @@ export class PikkuRPCService<
|
|
|
438
426
|
// Convenience function for initializing
|
|
439
427
|
getContextRPCService(
|
|
440
428
|
services: Services,
|
|
441
|
-
wire:
|
|
429
|
+
wire: PikkuRawWire,
|
|
442
430
|
requiresAuthOrOptions?:
|
|
443
431
|
| boolean
|
|
444
432
|
| {
|
|
@@ -456,7 +444,7 @@ export class PikkuRPCService<
|
|
|
456
444
|
: { requiresAuth: requiresAuthOrOptions }
|
|
457
445
|
const serviceRPC = new ContextAwareRPCService(
|
|
458
446
|
services,
|
|
459
|
-
wire,
|
|
447
|
+
wire as PikkuWire,
|
|
460
448
|
options,
|
|
461
449
|
packageName
|
|
462
450
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PikkuRawWire, 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
4
|
import {
|
|
@@ -97,7 +97,7 @@ export async function runScheduledTask({
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
// Create the scheduled task wire object
|
|
100
|
-
const wire:
|
|
100
|
+
const wire: PikkuRawWire = {
|
|
101
101
|
traceId: resolvedTraceId,
|
|
102
102
|
scheduledTask: {
|
|
103
103
|
name,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PikkuRawWire } from '../../types/core.types.js'
|
|
2
2
|
import type {
|
|
3
3
|
CoreTrigger,
|
|
4
4
|
CoreTriggerSource,
|
|
@@ -99,7 +99,7 @@ export async function setupTrigger<TInput = unknown, TOutput = unknown>({
|
|
|
99
99
|
)
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
const wire:
|
|
102
|
+
const wire: PikkuRawWire = {
|
|
103
103
|
trigger: {
|
|
104
104
|
invoke: (data: unknown) => {
|
|
105
105
|
singletonServices.logger.info(`Trigger fired: ${name}`)
|
|
@@ -10,10 +10,11 @@ import {
|
|
|
10
10
|
} from './pikku-workflow-service.js'
|
|
11
11
|
|
|
12
12
|
describe('pikku-workflow-service worker registration', () => {
|
|
13
|
-
test('registers sleeper function metadata', () => {
|
|
13
|
+
test('registers sleeper function metadata after wireQueueWorkers', () => {
|
|
14
14
|
resetPikkuState()
|
|
15
15
|
|
|
16
|
-
new InMemoryWorkflowService()
|
|
16
|
+
const ws = new InMemoryWorkflowService()
|
|
17
|
+
ws.wireQueueWorkers()
|
|
17
18
|
|
|
18
19
|
const functionMeta = pikkuState(null, 'function', 'meta')
|
|
19
20
|
assert.deepEqual(functionMeta.pikkuWorkflowSleeper, {
|
|
@@ -126,19 +127,19 @@ describe('pikku-workflow-service run-level inline', () => {
|
|
|
126
127
|
describe('pikku-workflow-service per-function step dispatch', () => {
|
|
127
128
|
// Expose the protected dispatchStep so we can assert the dispatch decision
|
|
128
129
|
// in isolation: a step queues only when its function opts out of inline
|
|
129
|
-
// execution (
|
|
130
|
+
// execution (workflowQueued: true).
|
|
130
131
|
class TestWorkflowService extends InMemoryWorkflowService {
|
|
131
132
|
public callDispatchStep(rpcName: string) {
|
|
132
133
|
return this.dispatchStep('run-1', 'step-1', rpcName, {})
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
const setupFunction = (rpcName: string,
|
|
137
|
+
const setupFunction = (rpcName: string, workflowQueued?: boolean) => {
|
|
137
138
|
pikkuState(null, 'rpc', 'meta')[rpcName] = rpcName as any
|
|
138
139
|
pikkuState(null, 'function', 'meta')[rpcName] = {
|
|
139
140
|
pikkuFuncId: rpcName,
|
|
140
141
|
sessionless: true,
|
|
141
|
-
...(
|
|
142
|
+
...(workflowQueued === undefined ? {} : { workflowQueued }),
|
|
142
143
|
} as any
|
|
143
144
|
}
|
|
144
145
|
|
|
@@ -166,7 +167,7 @@ describe('pikku-workflow-service per-function step dispatch', () => {
|
|
|
166
167
|
cleanup('defaultInlineStep')
|
|
167
168
|
})
|
|
168
169
|
|
|
169
|
-
test('
|
|
170
|
+
test('workflowQueued: true step IS dispatched to the queue when a queueService exists', async () => {
|
|
170
171
|
const ws = new TestWorkflowService()
|
|
171
172
|
let queued = false
|
|
172
173
|
pikkuState(null, 'package', 'singletonServices', {
|
|
@@ -178,36 +179,25 @@ describe('pikku-workflow-service per-function step dispatch', () => {
|
|
|
178
179
|
},
|
|
179
180
|
} as any)
|
|
180
181
|
|
|
181
|
-
setupFunction('queuedStep',
|
|
182
|
+
setupFunction('queuedStep', true)
|
|
182
183
|
const dispatched = await ws.callDispatchStep('queuedStep')
|
|
183
|
-
assert.equal(dispatched, true, '
|
|
184
|
-
assert.equal(queued, true, '
|
|
184
|
+
assert.equal(dispatched, true, 'workflowQueued step should dispatch')
|
|
185
|
+
assert.equal(queued, true, 'workflowQueued step should queue')
|
|
185
186
|
cleanup('queuedStep')
|
|
186
187
|
})
|
|
187
188
|
|
|
188
|
-
test('
|
|
189
|
+
test('workflowQueued: true step throws when no queueService is configured', async () => {
|
|
189
190
|
const ws = new TestWorkflowService()
|
|
190
|
-
let warned = false
|
|
191
191
|
pikkuState(null, 'package', 'singletonServices', {
|
|
192
|
-
logger: {
|
|
193
|
-
error() {},
|
|
194
|
-
info() {},
|
|
195
|
-
warn: () => {
|
|
196
|
-
warned = true
|
|
197
|
-
},
|
|
198
|
-
debug() {},
|
|
199
|
-
},
|
|
192
|
+
logger: { error() {}, info() {}, warn() {}, debug() {} },
|
|
200
193
|
// no queueService
|
|
201
194
|
} as any)
|
|
202
195
|
|
|
203
|
-
setupFunction('queuedStepNoQueue',
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
false,
|
|
208
|
-
'falls back to inline when no queue service'
|
|
196
|
+
setupFunction('queuedStepNoQueue', true)
|
|
197
|
+
await assert.rejects(
|
|
198
|
+
() => ws.callDispatchStep('queuedStepNoQueue'),
|
|
199
|
+
/workflowQueued: true.*no queue service/i
|
|
209
200
|
)
|
|
210
|
-
assert.equal(warned, true, 'should warn about the misconfiguration')
|
|
211
201
|
cleanup('queuedStepNoQueue')
|
|
212
202
|
})
|
|
213
203
|
})
|