@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.
- package/CHANGELOG.md +24 -0
- package/dist/errors/error-handler.js +3 -3
- package/dist/function/function-runner.d.ts +4 -3
- package/dist/function/function-runner.js +60 -14
- package/dist/function/functions.types.d.ts +84 -5
- package/dist/function/functions.types.js +41 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +5 -2
- package/dist/middleware/auth-apikey.d.ts +1 -1
- package/dist/middleware/auth-bearer.d.ts +1 -1
- package/dist/middleware/auth-cookie.d.ts +1 -1
- package/dist/middleware/timeout.d.ts +1 -1
- package/dist/middleware-runner.d.ts +3 -14
- package/dist/middleware-runner.js +8 -8
- package/dist/permissions.d.ts +3 -86
- package/dist/permissions.js +11 -67
- package/dist/pikku-state.d.ts +32 -104
- package/dist/pikku-state.js +140 -66
- package/dist/schema.d.ts +8 -6
- package/dist/schema.js +25 -13
- package/dist/services/workflow-service.d.ts +38 -0
- package/dist/services/workflow-service.js +1 -0
- package/dist/types/core.types.d.ts +12 -4
- package/dist/types/core.types.js +1 -1
- package/dist/types/state.types.d.ts +135 -0
- package/dist/types/state.types.js +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +45 -0
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/channel-runner.js +5 -5
- package/dist/wirings/channel/log-channels.js +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -2
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
- package/dist/wirings/cli/cli-runner.js +10 -10
- package/dist/wirings/cli/cli.types.d.ts +1 -0
- package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
- package/dist/wirings/forge-node/forge-node.types.js +38 -0
- package/dist/wirings/forge-node/index.d.ts +1 -0
- package/dist/wirings/forge-node/index.js +1 -0
- package/dist/wirings/http/http-runner.d.ts +2 -2
- package/dist/wirings/http/http-runner.js +21 -12
- package/dist/wirings/http/http.types.d.ts +14 -1
- package/dist/wirings/http/log-http-routes.js +1 -1
- package/dist/wirings/http/routers/path-to-regex.js +2 -2
- package/dist/wirings/mcp/mcp-runner.js +21 -21
- package/dist/wirings/queue/queue-runner.js +6 -6
- package/dist/wirings/rpc/index.d.ts +1 -1
- package/dist/wirings/rpc/index.js +1 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +7 -8
- package/dist/wirings/rpc/rpc-runner.js +62 -14
- package/dist/wirings/rpc/rpc-types.d.ts +7 -0
- package/dist/wirings/scheduler/log-schedulers.js +1 -1
- package/dist/wirings/scheduler/scheduler-runner.js +5 -5
- package/dist/wirings/trigger/index.d.ts +2 -0
- package/dist/wirings/trigger/index.js +2 -0
- package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
- package/dist/wirings/trigger/trigger-runner.js +57 -0
- package/dist/wirings/trigger/trigger.types.d.ts +42 -0
- package/dist/wirings/trigger/trigger.types.js +1 -0
- package/dist/wirings/workflow/dsl/index.d.ts +5 -0
- package/dist/wirings/workflow/dsl/index.js +4 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
- package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
- package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
- package/dist/wirings/workflow/graph/graph-node.js +58 -0
- package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
- package/dist/wirings/workflow/graph/graph-runner.js +452 -0
- package/dist/wirings/workflow/graph/index.d.ts +3 -0
- package/dist/wirings/workflow/graph/index.js +3 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
- package/dist/wirings/workflow/index.d.ts +7 -12
- package/dist/wirings/workflow/index.js +6 -11
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +96 -6
- package/dist/wirings/workflow/pikku-workflow-service.js +230 -103
- package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
- package/dist/wirings/workflow/wire-workflow.js +53 -0
- package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
- package/dist/wirings/workflow/workflow-utils.js +66 -0
- package/dist/wirings/workflow/workflow.types.d.ts +133 -211
- package/package.json +10 -1
- package/src/errors/error-handler.ts +3 -3
- package/src/function/function-runner.test.ts +1 -1
- package/src/function/function-runner.ts +86 -16
- package/src/function/functions.types.ts +126 -4
- package/src/index.ts +10 -5
- package/src/middleware-runner.ts +16 -9
- package/src/permissions.test.ts +28 -86
- package/src/permissions.ts +21 -80
- package/src/pikku-state.ts +156 -201
- package/src/schema.ts +42 -13
- package/src/services/workflow-service.ts +74 -0
- package/src/types/core.types.ts +12 -3
- package/src/types/state.types.ts +195 -0
- package/src/utils.ts +55 -0
- package/src/wirings/channel/channel-handler.ts +1 -1
- package/src/wirings/channel/channel-runner.ts +5 -5
- package/src/wirings/channel/local/local-channel-runner.test.ts +3 -1
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -2
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
- package/src/wirings/cli/cli-runner.test.ts +19 -19
- package/src/wirings/cli/cli-runner.ts +10 -9
- package/src/wirings/cli/cli.types.ts +1 -0
- package/src/wirings/forge-node/forge-node.types.ts +135 -0
- package/src/wirings/forge-node/index.ts +1 -0
- package/src/wirings/http/http-runner.test.ts +2 -2
- package/src/wirings/http/http-runner.ts +30 -13
- package/src/wirings/http/http.types.ts +14 -0
- package/src/wirings/http/log-http-routes.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
- package/src/wirings/http/routers/path-to-regex.ts +2 -2
- package/src/wirings/mcp/mcp-runner.ts +21 -21
- package/src/wirings/queue/queue-runner.test.ts +19 -19
- package/src/wirings/queue/queue-runner.ts +6 -6
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +88 -22
- package/src/wirings/rpc/rpc-types.ts +8 -0
- package/src/wirings/scheduler/log-schedulers.ts +1 -1
- package/src/wirings/scheduler/scheduler-runner.test.ts +27 -27
- package/src/wirings/scheduler/scheduler-runner.ts +5 -5
- package/src/wirings/trigger/index.ts +2 -0
- package/src/wirings/trigger/trigger-runner.ts +96 -0
- package/src/wirings/trigger/trigger.types.ts +56 -0
- package/src/wirings/workflow/dsl/index.ts +30 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
- package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
- package/src/wirings/workflow/graph/graph-node.ts +227 -0
- package/src/wirings/workflow/graph/graph-runner.ts +694 -0
- package/src/wirings/workflow/graph/index.ts +3 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
- package/src/wirings/workflow/index.ts +53 -26
- package/src/wirings/workflow/pikku-workflow-service.ts +333 -117
- package/src/wirings/workflow/wire-workflow.ts +94 -0
- package/src/wirings/workflow/workflow-utils.ts +120 -0
- package/src/wirings/workflow/workflow.types.ts +166 -277
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/workflow/workflow-runner.d.ts +0 -34
- package/dist/wirings/workflow/workflow-runner.js +0 -65
- package/src/function/function-runner.ts.bak +0 -188
- package/src/wirings/workflow/workflow-runner.ts +0 -72
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SerializedError,
|
|
3
|
+
CoreSingletonServices,
|
|
4
|
+
CreateWireServices,
|
|
5
|
+
CoreConfig,
|
|
6
|
+
} from '../types/core.types.js'
|
|
7
|
+
import {
|
|
8
|
+
WorkflowRun,
|
|
9
|
+
StepState,
|
|
10
|
+
WorkflowStatus,
|
|
11
|
+
} from '../wirings/workflow/workflow.types.js'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Interface for workflow orchestration
|
|
15
|
+
* Handles workflow execution, replay, orchestration logic, and run-level state
|
|
16
|
+
*/
|
|
17
|
+
export interface WorkflowService {
|
|
18
|
+
// Run-level state operations
|
|
19
|
+
createRun(workflowName: string, input: any, inline?: boolean): Promise<string>
|
|
20
|
+
getRun(id: string): Promise<WorkflowRun | null>
|
|
21
|
+
getRunHistory(runId: string): Promise<Array<StepState & { stepName: string }>>
|
|
22
|
+
updateRunStatus(
|
|
23
|
+
id: string,
|
|
24
|
+
status: WorkflowStatus,
|
|
25
|
+
output?: any,
|
|
26
|
+
error?: SerializedError
|
|
27
|
+
): Promise<void>
|
|
28
|
+
withRunLock<T>(id: string, fn: () => Promise<T>): Promise<T>
|
|
29
|
+
close(): Promise<void>
|
|
30
|
+
|
|
31
|
+
// Orchestration operations
|
|
32
|
+
resumeWorkflow(runId: string): Promise<void>
|
|
33
|
+
setServices(
|
|
34
|
+
singletonServices: CoreSingletonServices,
|
|
35
|
+
createWireServices: CreateWireServices,
|
|
36
|
+
config: CoreConfig
|
|
37
|
+
): void
|
|
38
|
+
startWorkflow<I>(
|
|
39
|
+
name: string,
|
|
40
|
+
input: I,
|
|
41
|
+
rpcService: any,
|
|
42
|
+
options?: { inline?: boolean; startNode?: string }
|
|
43
|
+
): Promise<{ runId: string }>
|
|
44
|
+
runWorkflowJob(runId: string, rpcService: any): Promise<void>
|
|
45
|
+
orchestrateWorkflow(runId: string, rpcService: any): Promise<void>
|
|
46
|
+
executeWorkflowSleepCompleted(runId: string, stepId: string): Promise<void>
|
|
47
|
+
|
|
48
|
+
// Step-level state operations
|
|
49
|
+
insertStepState(
|
|
50
|
+
runId: string,
|
|
51
|
+
stepName: string,
|
|
52
|
+
rpcName: string,
|
|
53
|
+
data: any,
|
|
54
|
+
stepOptions?: { retries?: number; retryDelay?: string | number }
|
|
55
|
+
): Promise<StepState>
|
|
56
|
+
getStepState(runId: string, stepName: string): Promise<StepState>
|
|
57
|
+
setStepRunning(stepId: string): Promise<void>
|
|
58
|
+
setStepScheduled(stepId: string): Promise<void>
|
|
59
|
+
setStepResult(stepId: string, result: any): Promise<void>
|
|
60
|
+
setStepError(stepId: string, error: Error): Promise<void>
|
|
61
|
+
createRetryAttempt(
|
|
62
|
+
stepId: string,
|
|
63
|
+
status: 'pending' | 'running'
|
|
64
|
+
): Promise<StepState>
|
|
65
|
+
|
|
66
|
+
// Step execution
|
|
67
|
+
executeWorkflowStep(
|
|
68
|
+
runId: string,
|
|
69
|
+
stepName: string,
|
|
70
|
+
rpcName: string | null,
|
|
71
|
+
data: any,
|
|
72
|
+
rpcService: any
|
|
73
|
+
): Promise<void>
|
|
74
|
+
}
|
package/src/types/core.types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Logger, LogLevel } from '../services/logger.js'
|
|
2
2
|
import { VariablesService } from '../services/variables-service.js'
|
|
3
|
+
import { SecretService } from '../services/secret-service.js'
|
|
3
4
|
import { SchemaService } from '../services/schema-service.js'
|
|
4
5
|
import { JWTService } from '../services/jwt-service.js'
|
|
5
6
|
import { PikkuHTTP } from '../wirings/http/http.types.js'
|
|
@@ -16,6 +17,8 @@ import {
|
|
|
16
17
|
WorkflowServiceConfig,
|
|
17
18
|
WorkflowStepWire,
|
|
18
19
|
} from '../wirings/workflow/workflow.types.js'
|
|
20
|
+
import type { PikkuGraphWire } from '../wirings/workflow/graph/workflow-graph.types.js'
|
|
21
|
+
import { PikkuTrigger } from '../wirings/trigger/trigger.types.js'
|
|
19
22
|
import { SchedulerService } from '../services/scheduler-service.js'
|
|
20
23
|
|
|
21
24
|
export type PikkuWiringTypes =
|
|
@@ -169,6 +172,8 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
|
169
172
|
logger: Logger
|
|
170
173
|
/** The variable service to be used */
|
|
171
174
|
variables: VariablesService
|
|
175
|
+
/** The secrets service to retrieve secrets */
|
|
176
|
+
secrets: SecretService
|
|
172
177
|
/** The workflow orchestrator service */
|
|
173
178
|
workflowService?: WorkflowService
|
|
174
179
|
/** The queue service */
|
|
@@ -189,6 +194,7 @@ export type PikkuWire<
|
|
|
189
194
|
IsChannel extends true | null = null,
|
|
190
195
|
MCPTools extends string | never = never,
|
|
191
196
|
TypedWorkflow extends PikkuWorkflowWire | never = PikkuWorkflowWire,
|
|
197
|
+
TriggerOutput = unknown,
|
|
192
198
|
> = Partial<{
|
|
193
199
|
http: PikkuHTTP<In>
|
|
194
200
|
mcp: PikkuMCP<MCPTools>
|
|
@@ -201,6 +207,8 @@ export type PikkuWire<
|
|
|
201
207
|
cli: PikkuCLI
|
|
202
208
|
workflow: TypedWorkflow
|
|
203
209
|
workflowStep: WorkflowStepWire
|
|
210
|
+
graph: PikkuGraphWire
|
|
211
|
+
trigger: PikkuTrigger<TriggerOutput>
|
|
204
212
|
initialSession: HasInitialSession extends true
|
|
205
213
|
? UserSession
|
|
206
214
|
: UserSession | undefined
|
|
@@ -231,8 +239,8 @@ export type CorePikkuMiddlewareConfig<
|
|
|
231
239
|
> = {
|
|
232
240
|
/** The middleware function */
|
|
233
241
|
func: CorePikkuMiddleware<SingletonServices, UserSession>
|
|
234
|
-
/** Optional human-readable
|
|
235
|
-
|
|
242
|
+
/** Optional human-readable title for the middleware */
|
|
243
|
+
title?: string
|
|
236
244
|
/** Optional description of what the middleware does */
|
|
237
245
|
description?: string
|
|
238
246
|
}
|
|
@@ -275,7 +283,7 @@ export type CorePikkuMiddlewareGroup<
|
|
|
275
283
|
*
|
|
276
284
|
* // Configuration object syntax with metadata
|
|
277
285
|
* export const logMiddleware = pikkuMiddleware({
|
|
278
|
-
*
|
|
286
|
+
* title: 'Request Logger',
|
|
279
287
|
* description: 'Logs request information',
|
|
280
288
|
* func: async ({ logger }, next) => {
|
|
281
289
|
* logger.info('Request started')
|
|
@@ -367,6 +375,7 @@ export type CreateConfig<
|
|
|
367
375
|
export type CommonWireMeta = {
|
|
368
376
|
pikkuFuncName: string
|
|
369
377
|
|
|
378
|
+
title?: string
|
|
370
379
|
tags?: string[]
|
|
371
380
|
summary?: string
|
|
372
381
|
description?: string
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { PikkuError, ErrorDetails } from '../errors/error-handler.js'
|
|
2
|
+
import {
|
|
3
|
+
CorePikkuFunctionConfig,
|
|
4
|
+
CorePermissionGroup,
|
|
5
|
+
CorePikkuPermission,
|
|
6
|
+
} from '../function/functions.types.js'
|
|
7
|
+
import { CoreChannel, ChannelsMeta } from '../wirings/channel/channel.types.js'
|
|
8
|
+
import { CLIMeta, CLIProgramState } from '../wirings/cli/cli.types.js'
|
|
9
|
+
import {
|
|
10
|
+
HTTPMethod,
|
|
11
|
+
CoreHTTPFunctionWiring,
|
|
12
|
+
HTTPWiringsMeta,
|
|
13
|
+
} from '../wirings/http/http.types.js'
|
|
14
|
+
import {
|
|
15
|
+
CoreMCPResource,
|
|
16
|
+
MCPResourceMeta,
|
|
17
|
+
CoreMCPTool,
|
|
18
|
+
MCPToolMeta,
|
|
19
|
+
CoreMCPPrompt,
|
|
20
|
+
MCPPromptMeta,
|
|
21
|
+
} from '../wirings/mcp/mcp.types.js'
|
|
22
|
+
import {
|
|
23
|
+
CoreQueueWorker,
|
|
24
|
+
QueueWorkersMeta,
|
|
25
|
+
} from '../wirings/queue/queue.types.js'
|
|
26
|
+
import {
|
|
27
|
+
CoreScheduledTask,
|
|
28
|
+
ScheduledTasksMeta,
|
|
29
|
+
} from '../wirings/scheduler/scheduler.types.js'
|
|
30
|
+
import {
|
|
31
|
+
CoreWorkflow,
|
|
32
|
+
WorkflowsRuntimeMeta,
|
|
33
|
+
WorkflowWires,
|
|
34
|
+
} from '../wirings/workflow/workflow.types.js'
|
|
35
|
+
import type {
|
|
36
|
+
WorkflowGraphDefinition,
|
|
37
|
+
GraphNodeConfig,
|
|
38
|
+
} from '../wirings/workflow/graph/workflow-graph.types.js'
|
|
39
|
+
import { CoreTrigger, TriggerMeta } from '../wirings/trigger/trigger.types.js'
|
|
40
|
+
import {
|
|
41
|
+
FunctionsMeta,
|
|
42
|
+
CorePikkuMiddleware,
|
|
43
|
+
CorePikkuMiddlewareGroup,
|
|
44
|
+
FunctionServicesMeta,
|
|
45
|
+
CreateConfig,
|
|
46
|
+
CreateSingletonServices,
|
|
47
|
+
CreateWireServices,
|
|
48
|
+
CoreConfig,
|
|
49
|
+
CoreSingletonServices,
|
|
50
|
+
CoreServices,
|
|
51
|
+
CoreUserSession,
|
|
52
|
+
} from './core.types.js'
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* State structure for an individual package
|
|
56
|
+
*/
|
|
57
|
+
export interface PikkuPackageState {
|
|
58
|
+
function: {
|
|
59
|
+
meta: FunctionsMeta
|
|
60
|
+
functions: Map<string, CorePikkuFunctionConfig<any, any>>
|
|
61
|
+
}
|
|
62
|
+
rpc: {
|
|
63
|
+
meta: Record<string, string>
|
|
64
|
+
files: Map<
|
|
65
|
+
string,
|
|
66
|
+
{
|
|
67
|
+
exportedName: string
|
|
68
|
+
path: string
|
|
69
|
+
}
|
|
70
|
+
>
|
|
71
|
+
/** Maps namespace aliases to package names (e.g., 'ext' -> '@pikku/templates-function-external') */
|
|
72
|
+
externalPackages: Map<string, string>
|
|
73
|
+
}
|
|
74
|
+
http: {
|
|
75
|
+
middleware: Map<string, CorePikkuMiddleware<any, any>[]>
|
|
76
|
+
permissions: Map<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
77
|
+
routes: Map<HTTPMethod, Map<string, CoreHTTPFunctionWiring<any, any, any>>>
|
|
78
|
+
meta: HTTPWiringsMeta
|
|
79
|
+
}
|
|
80
|
+
channel: {
|
|
81
|
+
channels: Map<string, CoreChannel<any, any>>
|
|
82
|
+
meta: ChannelsMeta
|
|
83
|
+
}
|
|
84
|
+
scheduler: {
|
|
85
|
+
tasks: Map<string, CoreScheduledTask>
|
|
86
|
+
meta: ScheduledTasksMeta
|
|
87
|
+
}
|
|
88
|
+
queue: {
|
|
89
|
+
registrations: Map<string, CoreQueueWorker>
|
|
90
|
+
meta: QueueWorkersMeta
|
|
91
|
+
}
|
|
92
|
+
workflows: {
|
|
93
|
+
registrations: Map<string, CoreWorkflow>
|
|
94
|
+
graphRegistrations: Map<string, WorkflowGraphDefinition<any>>
|
|
95
|
+
/** DSL workflow wirings (from wireWorkflow({ func: ... })) */
|
|
96
|
+
wirings: Map<any, { wires: WorkflowWires; func: any }>
|
|
97
|
+
/** Graph workflow wirings (from wireWorkflow({ graph: ... })) */
|
|
98
|
+
graphWirings: Map<
|
|
99
|
+
any,
|
|
100
|
+
{ wires: WorkflowWires; graph: Record<string, GraphNodeConfig<string>> }
|
|
101
|
+
>
|
|
102
|
+
meta: WorkflowsRuntimeMeta
|
|
103
|
+
}
|
|
104
|
+
trigger: {
|
|
105
|
+
triggers: Map<string, CoreTrigger>
|
|
106
|
+
meta: TriggerMeta
|
|
107
|
+
}
|
|
108
|
+
mcp: {
|
|
109
|
+
resources: Map<string, CoreMCPResource>
|
|
110
|
+
resourcesMeta: MCPResourceMeta
|
|
111
|
+
tools: Map<string, CoreMCPTool>
|
|
112
|
+
toolsMeta: MCPToolMeta
|
|
113
|
+
prompts: Map<string, CoreMCPPrompt>
|
|
114
|
+
promptsMeta: MCPPromptMeta
|
|
115
|
+
}
|
|
116
|
+
cli: {
|
|
117
|
+
meta: CLIMeta | Record<string, any> // Backward compatible with old published CLI format
|
|
118
|
+
programs: Record<string, CLIProgramState>
|
|
119
|
+
}
|
|
120
|
+
middleware: {
|
|
121
|
+
tagGroup: Record<string, CorePikkuMiddlewareGroup>
|
|
122
|
+
httpGroup: Record<string, CorePikkuMiddlewareGroup>
|
|
123
|
+
tagGroupMeta: Record<
|
|
124
|
+
string,
|
|
125
|
+
{
|
|
126
|
+
exportName: string | null
|
|
127
|
+
sourceFile: string
|
|
128
|
+
position: number
|
|
129
|
+
services: FunctionServicesMeta
|
|
130
|
+
middlewareCount: number
|
|
131
|
+
isFactory: boolean
|
|
132
|
+
}
|
|
133
|
+
>
|
|
134
|
+
httpGroupMeta: Record<
|
|
135
|
+
string,
|
|
136
|
+
{
|
|
137
|
+
exportName: string | null
|
|
138
|
+
sourceFile: string
|
|
139
|
+
position: number
|
|
140
|
+
services: FunctionServicesMeta
|
|
141
|
+
middlewareCount: number
|
|
142
|
+
isFactory: boolean
|
|
143
|
+
}
|
|
144
|
+
>
|
|
145
|
+
}
|
|
146
|
+
permissions: {
|
|
147
|
+
tagGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
148
|
+
httpGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
149
|
+
tagGroupMeta: Record<
|
|
150
|
+
string,
|
|
151
|
+
{
|
|
152
|
+
exportName: string | null
|
|
153
|
+
sourceFile: string
|
|
154
|
+
position: number
|
|
155
|
+
services: FunctionServicesMeta
|
|
156
|
+
permissionCount: number
|
|
157
|
+
isFactory: boolean
|
|
158
|
+
}
|
|
159
|
+
>
|
|
160
|
+
httpGroupMeta: Record<
|
|
161
|
+
string,
|
|
162
|
+
{
|
|
163
|
+
exportName: string | null
|
|
164
|
+
sourceFile: string
|
|
165
|
+
position: number
|
|
166
|
+
services: FunctionServicesMeta
|
|
167
|
+
permissionCount: number
|
|
168
|
+
isFactory: boolean
|
|
169
|
+
}
|
|
170
|
+
>
|
|
171
|
+
}
|
|
172
|
+
misc: {
|
|
173
|
+
errors: Map<PikkuError, ErrorDetails>
|
|
174
|
+
schemas: Map<string, any>
|
|
175
|
+
middleware: Record<string, CorePikkuMiddleware[]>
|
|
176
|
+
permissions: Record<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
177
|
+
}
|
|
178
|
+
package: {
|
|
179
|
+
/** Service factory functions for external packages */
|
|
180
|
+
factories: {
|
|
181
|
+
createConfig?: CreateConfig<CoreConfig>
|
|
182
|
+
createSingletonServices?: CreateSingletonServices<
|
|
183
|
+
CoreConfig,
|
|
184
|
+
CoreSingletonServices
|
|
185
|
+
>
|
|
186
|
+
createWireServices?: CreateWireServices<
|
|
187
|
+
CoreSingletonServices,
|
|
188
|
+
CoreServices,
|
|
189
|
+
CoreUserSession
|
|
190
|
+
>
|
|
191
|
+
} | null
|
|
192
|
+
/** Cached singleton services for this package */
|
|
193
|
+
singletonServices: CoreSingletonServices | null
|
|
194
|
+
}
|
|
195
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Logger } from './services/logger.js'
|
|
2
|
+
import { CoreSingletonServices } from './types/core.types.js'
|
|
2
3
|
|
|
3
4
|
// TODO: WireServices probably needs it's own type
|
|
4
5
|
// but is an issue for the future and will be tackled
|
|
@@ -57,3 +58,57 @@ export const freezeDedupe = <T>(
|
|
|
57
58
|
}
|
|
58
59
|
return Object.freeze(out)
|
|
59
60
|
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Stop a single service by calling its stop method if it exists
|
|
64
|
+
*/
|
|
65
|
+
const stopService = async (
|
|
66
|
+
logger: Logger,
|
|
67
|
+
name: string,
|
|
68
|
+
service: any
|
|
69
|
+
): Promise<void> => {
|
|
70
|
+
const stop = service?.stop
|
|
71
|
+
if (stop) {
|
|
72
|
+
logger.info(`Stopping singleton service: ${name}`)
|
|
73
|
+
try {
|
|
74
|
+
await stop.call(service)
|
|
75
|
+
} catch (e: any) {
|
|
76
|
+
logger.error(`Error stopping service ${name}:`, e)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Stop all singleton services, including external package services.
|
|
83
|
+
* External package services are stopped first, then the parent services.
|
|
84
|
+
*
|
|
85
|
+
* @param singletonServices - The parent singleton services to stop
|
|
86
|
+
*/
|
|
87
|
+
export const stopSingletonServices = async (
|
|
88
|
+
singletonServices: CoreSingletonServices
|
|
89
|
+
): Promise<void> => {
|
|
90
|
+
const logger = singletonServices.logger
|
|
91
|
+
|
|
92
|
+
// First, stop all external package singleton services
|
|
93
|
+
if (globalThis.pikkuState) {
|
|
94
|
+
for (const [packageName, packageState] of globalThis.pikkuState) {
|
|
95
|
+
// Skip main package - we handle it separately
|
|
96
|
+
if (packageName === '__main__') continue
|
|
97
|
+
|
|
98
|
+
const packageServices = packageState.package?.singletonServices
|
|
99
|
+
if (packageServices) {
|
|
100
|
+
logger.info(`Stopping singleton services for package: ${packageName}`)
|
|
101
|
+
for (const [name, service] of Object.entries(packageServices)) {
|
|
102
|
+
await stopService(logger, `${packageName}/${name}`, service)
|
|
103
|
+
}
|
|
104
|
+
// Clear the cached services
|
|
105
|
+
packageState.package.singletonServices = null
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Then stop the parent singleton services
|
|
111
|
+
for (const [name, service] of Object.entries(singletonServices)) {
|
|
112
|
+
await stopService(logger, name, service)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -17,7 +17,7 @@ const getRouteMeta = (
|
|
|
17
17
|
routingProperty?: string,
|
|
18
18
|
routerValue?: string
|
|
19
19
|
): ChannelMessageMeta => {
|
|
20
|
-
const channelMeta = pikkuState('channel', 'meta')[channelName]
|
|
20
|
+
const channelMeta = pikkuState(null, 'channel', 'meta')[channelName]
|
|
21
21
|
if (!channelMeta) {
|
|
22
22
|
throw new Error(`Channel ${channelName} not found`)
|
|
23
23
|
}
|
|
@@ -33,13 +33,13 @@ export const wireChannel = <
|
|
|
33
33
|
>
|
|
34
34
|
) => {
|
|
35
35
|
// Get the channel metadata
|
|
36
|
-
const channelsMeta = pikkuState('channel', 'meta')
|
|
36
|
+
const channelsMeta = pikkuState(null, 'channel', 'meta')
|
|
37
37
|
const channelMeta = channelsMeta[channel.name]
|
|
38
38
|
if (!channelMeta) {
|
|
39
39
|
throw new Error(`Channel metadata not found for channel: ${channel.name}`)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
pikkuState('channel', 'channels').set(channel.name, channel as any)
|
|
42
|
+
pikkuState(null, 'channel', 'channels').set(channel.name, channel as any)
|
|
43
43
|
|
|
44
44
|
// Register onConnect function if provided
|
|
45
45
|
if (channel.onConnect && channelMeta.connect) {
|
|
@@ -89,7 +89,7 @@ export const wireChannel = <
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// Store the channel configuration
|
|
92
|
-
pikkuState('channel', 'channels').set(channel.name, channel as any)
|
|
92
|
+
pikkuState(null, 'channel', 'channels').set(channel.name, channel as any)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
const getMatchingChannelConfig = (path: string) => {
|
|
@@ -98,7 +98,7 @@ const getMatchingChannelConfig = (path: string) => {
|
|
|
98
98
|
return null
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
const meta = pikkuState('channel', 'meta')
|
|
101
|
+
const meta = pikkuState(null, 'channel', 'meta')
|
|
102
102
|
const channelMeta = Object.values(meta).find(
|
|
103
103
|
(channelConfig) => channelConfig.route === matchedPath.route
|
|
104
104
|
)
|
|
@@ -106,7 +106,7 @@ const getMatchingChannelConfig = (path: string) => {
|
|
|
106
106
|
return null
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
const channels = pikkuState('channel', 'channels')
|
|
109
|
+
const channels = pikkuState(null, 'channel', 'channels')
|
|
110
110
|
const channelConfig = channels.get(channelMeta.name)
|
|
111
111
|
if (!channelConfig) {
|
|
112
112
|
return null
|
|
@@ -101,10 +101,12 @@ const mockCreateWireServices = async () => ({
|
|
|
101
101
|
|
|
102
102
|
beforeEach(() => {
|
|
103
103
|
resetPikkuState()
|
|
104
|
+
httpRouter.reset()
|
|
104
105
|
})
|
|
105
106
|
|
|
106
107
|
afterEach(() => {
|
|
107
108
|
resetPikkuState()
|
|
109
|
+
httpRouter.reset()
|
|
108
110
|
})
|
|
109
111
|
|
|
110
112
|
test('runChannel should return undefined and 404 if no matching channel is found', async () => {
|
|
@@ -130,7 +132,7 @@ test('runChannel should return undefined and 404 if no matching channel is found
|
|
|
130
132
|
test('runChannel should return a channel handler if channel matches and no auth required', async () => {
|
|
131
133
|
resetPikkuState()
|
|
132
134
|
|
|
133
|
-
pikkuState('channel', 'meta', {
|
|
135
|
+
pikkuState(null, 'channel', 'meta', {
|
|
134
136
|
test: {
|
|
135
137
|
name: 'test',
|
|
136
138
|
route: '/test-channel',
|
|
@@ -6,7 +6,7 @@ import { Logger } from '../../services/index.js'
|
|
|
6
6
|
* @param logger - A logger for logging information.
|
|
7
7
|
*/
|
|
8
8
|
export const logChannels = (logger: Logger) => {
|
|
9
|
-
const channels = pikkuState('channel', 'channels')
|
|
9
|
+
const channels = pikkuState(null, 'channel', 'channels')
|
|
10
10
|
if (channels.size === 0) {
|
|
11
11
|
logger.info('No channels added')
|
|
12
12
|
return
|
|
@@ -35,9 +35,9 @@ const getVariablesForChannel = ({
|
|
|
35
35
|
channelHandlerFactory: PikkuChannelHandlerFactory
|
|
36
36
|
openingData?: unknown
|
|
37
37
|
}) => {
|
|
38
|
-
const channels = pikkuState('channel', 'channels')
|
|
38
|
+
const channels = pikkuState(null, 'channel', 'channels')
|
|
39
39
|
const channelConfig = channels.get(channelName)
|
|
40
|
-
const channelsMeta = pikkuState('channel', 'meta')
|
|
40
|
+
const channelsMeta = pikkuState(null, 'channel', 'meta')
|
|
41
41
|
const meta = channelsMeta[channelName]
|
|
42
42
|
if (!channelConfig) {
|
|
43
43
|
throw new Error(`Channel not found: ${channelName}`)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pikkuState } from '../../../pikku-state.js'
|
|
2
|
-
import { CorePikkuCLIRender, CLIMeta } from '../cli.types.js'
|
|
2
|
+
import { CorePikkuCLIRender, type CLIMeta } from '../cli.types.js'
|
|
3
3
|
import { generateCommandHelp, parseCLIArguments } from '../command-parser.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -27,12 +27,13 @@ export async function executeCLIViaChannel({
|
|
|
27
27
|
defaultRenderer?: CorePikkuCLIRender<any>
|
|
28
28
|
}): Promise<void> {
|
|
29
29
|
// Get CLI metadata from state
|
|
30
|
-
const
|
|
31
|
-
if (!
|
|
30
|
+
const cliMeta = pikkuState(null, 'cli', 'meta')
|
|
31
|
+
if (!cliMeta || !('programs' in cliMeta)) {
|
|
32
32
|
throw new Error(
|
|
33
33
|
'[PKU342] CLI metadata not found. No CLI wirings were registered. See https://pikku.dev/docs/pikku-cli/errors/pku342 for more information.'
|
|
34
34
|
)
|
|
35
35
|
}
|
|
36
|
+
const allCLIMeta = cliMeta as CLIMeta
|
|
36
37
|
const programMeta = allCLIMeta.programs[programName]
|
|
37
38
|
|
|
38
39
|
if (!programMeta) {
|
|
@@ -30,7 +30,7 @@ describe('CLI Runner', () => {
|
|
|
30
30
|
|
|
31
31
|
describe('runCLICommand', () => {
|
|
32
32
|
test('should throw NotFoundError when program not found', async () => {
|
|
33
|
-
pikkuState('cli', 'meta', { programs: {}, renderers: {} })
|
|
33
|
+
pikkuState(null, 'cli', 'meta', { programs: {}, renderers: {} })
|
|
34
34
|
|
|
35
35
|
await assert.rejects(
|
|
36
36
|
async () =>
|
|
@@ -45,7 +45,7 @@ describe('CLI Runner', () => {
|
|
|
45
45
|
})
|
|
46
46
|
|
|
47
47
|
test('should throw NotFoundError when command not found', async () => {
|
|
48
|
-
pikkuState('cli', 'meta', {
|
|
48
|
+
pikkuState(null, 'cli', 'meta', {
|
|
49
49
|
programs: {
|
|
50
50
|
'test-cli': {
|
|
51
51
|
program: 'test-cli',
|
|
@@ -56,7 +56,7 @@ describe('CLI Runner', () => {
|
|
|
56
56
|
renderers: {},
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
pikkuState('cli', 'programs', {
|
|
59
|
+
pikkuState(null, 'cli', 'programs', {
|
|
60
60
|
'test-cli': {
|
|
61
61
|
defaultRenderer: undefined,
|
|
62
62
|
middleware: [],
|
|
@@ -84,7 +84,7 @@ describe('CLI Runner', () => {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
// Setup metadata
|
|
87
|
-
pikkuState('cli', 'meta', {
|
|
87
|
+
pikkuState(null, 'cli', 'meta', {
|
|
88
88
|
programs: {
|
|
89
89
|
'test-cli': {
|
|
90
90
|
program: 'test-cli',
|
|
@@ -102,7 +102,7 @@ describe('CLI Runner', () => {
|
|
|
102
102
|
renderers: {},
|
|
103
103
|
})
|
|
104
104
|
|
|
105
|
-
pikkuState('cli', 'programs', {
|
|
105
|
+
pikkuState(null, 'cli', 'programs', {
|
|
106
106
|
'test-cli': {
|
|
107
107
|
defaultRenderer: undefined,
|
|
108
108
|
middleware: [],
|
|
@@ -110,7 +110,7 @@ describe('CLI Runner', () => {
|
|
|
110
110
|
},
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
-
pikkuState('function', 'meta', {
|
|
113
|
+
pikkuState(null, 'function', 'meta', {
|
|
114
114
|
greetFunc: {
|
|
115
115
|
pikkuFuncName: 'greetFunc',
|
|
116
116
|
inputSchemaName: null,
|
|
@@ -148,7 +148,7 @@ describe('CLI Runner', () => {
|
|
|
148
148
|
return { success: true }
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
pikkuState('cli', 'meta', {
|
|
151
|
+
pikkuState(null, 'cli', 'meta', {
|
|
152
152
|
programs: {
|
|
153
153
|
'test-cli': {
|
|
154
154
|
program: 'test-cli',
|
|
@@ -166,7 +166,7 @@ describe('CLI Runner', () => {
|
|
|
166
166
|
renderers: {},
|
|
167
167
|
})
|
|
168
168
|
|
|
169
|
-
pikkuState('cli', 'programs', {
|
|
169
|
+
pikkuState(null, 'cli', 'programs', {
|
|
170
170
|
'test-cli': {
|
|
171
171
|
defaultRenderer: undefined,
|
|
172
172
|
middleware: [testMiddleware],
|
|
@@ -174,7 +174,7 @@ describe('CLI Runner', () => {
|
|
|
174
174
|
},
|
|
175
175
|
})
|
|
176
176
|
|
|
177
|
-
pikkuState('function', 'meta', {
|
|
177
|
+
pikkuState(null, 'function', 'meta', {
|
|
178
178
|
testFunc: {
|
|
179
179
|
pikkuFuncName: 'testFunc',
|
|
180
180
|
inputSchemaName: null,
|
|
@@ -208,7 +208,7 @@ describe('CLI Runner', () => {
|
|
|
208
208
|
|
|
209
209
|
const testFunc = async () => ({ success: true })
|
|
210
210
|
|
|
211
|
-
pikkuState('cli', 'meta', {
|
|
211
|
+
pikkuState(null, 'cli', 'meta', {
|
|
212
212
|
programs: {
|
|
213
213
|
'test-cli': {
|
|
214
214
|
program: 'test-cli',
|
|
@@ -226,7 +226,7 @@ describe('CLI Runner', () => {
|
|
|
226
226
|
renderers: {},
|
|
227
227
|
})
|
|
228
228
|
|
|
229
|
-
pikkuState('cli', 'programs', {
|
|
229
|
+
pikkuState(null, 'cli', 'programs', {
|
|
230
230
|
'test-cli': {
|
|
231
231
|
defaultRenderer: undefined,
|
|
232
232
|
middleware: [testMiddleware],
|
|
@@ -234,7 +234,7 @@ describe('CLI Runner', () => {
|
|
|
234
234
|
},
|
|
235
235
|
})
|
|
236
236
|
|
|
237
|
-
pikkuState('function', 'meta', {
|
|
237
|
+
pikkuState(null, 'function', 'meta', {
|
|
238
238
|
greetFunc: {
|
|
239
239
|
pikkuFuncName: 'greetFunc',
|
|
240
240
|
inputSchemaName: null,
|
|
@@ -260,7 +260,7 @@ describe('CLI Runner', () => {
|
|
|
260
260
|
test('should throw error when auth required but no session', async () => {
|
|
261
261
|
const testFunc = async () => ({ success: true })
|
|
262
262
|
|
|
263
|
-
pikkuState('cli', 'meta', {
|
|
263
|
+
pikkuState(null, 'cli', 'meta', {
|
|
264
264
|
programs: {
|
|
265
265
|
'test-cli': {
|
|
266
266
|
program: 'test-cli',
|
|
@@ -278,7 +278,7 @@ describe('CLI Runner', () => {
|
|
|
278
278
|
renderers: {},
|
|
279
279
|
})
|
|
280
280
|
|
|
281
|
-
pikkuState('function', 'meta', {
|
|
281
|
+
pikkuState(null, 'function', 'meta', {
|
|
282
282
|
secureFunc: {
|
|
283
283
|
pikkuFuncName: 'secureFunc',
|
|
284
284
|
inputSchemaName: null,
|
|
@@ -306,7 +306,7 @@ describe('CLI Runner', () => {
|
|
|
306
306
|
test('should register CLI program and commands', () => {
|
|
307
307
|
const greetFunc = async () => 'Hello'
|
|
308
308
|
|
|
309
|
-
pikkuState('cli', 'meta', {
|
|
309
|
+
pikkuState(null, 'cli', 'meta', {
|
|
310
310
|
programs: {
|
|
311
311
|
'my-cli': {
|
|
312
312
|
program: 'my-cli',
|
|
@@ -337,7 +337,7 @@ describe('CLI Runner', () => {
|
|
|
337
337
|
},
|
|
338
338
|
})
|
|
339
339
|
|
|
340
|
-
const programs = pikkuState('cli', 'programs')
|
|
340
|
+
const programs = pikkuState(null, 'cli', 'programs')
|
|
341
341
|
assert.ok(programs['my-cli'])
|
|
342
342
|
assert.strictEqual(programs['my-cli'].middleware.length, 0)
|
|
343
343
|
})
|
|
@@ -347,7 +347,7 @@ describe('CLI Runner', () => {
|
|
|
347
347
|
await next()
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
-
pikkuState('cli', 'meta', {
|
|
350
|
+
pikkuState(null, 'cli', 'meta', {
|
|
351
351
|
programs: {
|
|
352
352
|
'my-cli': {
|
|
353
353
|
program: 'my-cli',
|
|
@@ -364,13 +364,13 @@ describe('CLI Runner', () => {
|
|
|
364
364
|
middleware: [middleware],
|
|
365
365
|
})
|
|
366
366
|
|
|
367
|
-
const programs = pikkuState('cli', 'programs')
|
|
367
|
+
const programs = pikkuState(null, 'cli', 'programs')
|
|
368
368
|
assert.strictEqual(programs['my-cli'].middleware.length, 1)
|
|
369
369
|
assert.strictEqual(programs['my-cli'].middleware[0], middleware)
|
|
370
370
|
})
|
|
371
371
|
|
|
372
372
|
test('should throw error when CLI metadata not found', () => {
|
|
373
|
-
pikkuState('cli', 'meta', { programs: {}, renderers: {} })
|
|
373
|
+
pikkuState(null, 'cli', 'meta', { programs: {}, renderers: {} })
|
|
374
374
|
|
|
375
375
|
assert.throws(() => {
|
|
376
376
|
wireCLI({
|