@pikku/core 0.12.13 → 0.12.15
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 +46 -0
- package/dist/errors/errors.d.ts +18 -0
- package/dist/errors/errors.js +33 -0
- package/dist/function/function-runner.d.ts +1 -1
- package/dist/function/function-runner.js +10 -5
- 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 +1 -2
- package/dist/index.js +1 -2
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/remote-auth.js +5 -2
- 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 +2 -4
- package/dist/remote.d.ts +10 -0
- package/dist/remote.js +32 -0
- package/dist/schema.js +2 -0
- package/dist/services/credential-service.d.ts +11 -0
- package/dist/services/credential-wire-service.d.ts +14 -3
- package/dist/services/credential-wire-service.js +49 -6
- 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/local-credential-service.d.ts +2 -0
- package/dist/services/local-credential-service.js +20 -0
- 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/pikku-user-id.d.ts +3 -0
- package/dist/services/pikku-user-id.js +16 -0
- package/dist/services/typed-credential-service.d.ts +2 -0
- package/dist/services/typed-credential-service.js +6 -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 +14 -2
- package/dist/types/state.types.d.ts +9 -2
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +21 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.js +90 -21
- package/dist/wirings/ai-agent/ai-agent-registry.js +2 -2
- package/dist/wirings/ai-agent/ai-agent-runner.js +24 -2
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +61 -3
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +25 -4
- package/dist/wirings/ai-agent/index.d.ts +1 -1
- package/dist/wirings/ai-agent/index.js +1 -1
- package/dist/wirings/channel/channel-runner.js +3 -3
- package/dist/wirings/cli/cli-runner.js +4 -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 -15
- package/dist/wirings/http/http.types.d.ts +2 -0
- package/dist/wirings/mcp/mcp-runner.js +5 -3
- package/dist/wirings/queue/queue-runner.d.ts +3 -1
- package/dist/wirings/queue/queue-runner.js +8 -3
- package/dist/wirings/queue/queue.types.d.ts +6 -0
- package/dist/wirings/rpc/rpc-runner.js +57 -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-dsl.types.d.ts +2 -0
- 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 +218 -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 +19 -1
- package/package.json +4 -1
- package/src/errors/errors.ts +44 -0
- package/src/function/function-runner.ts +24 -13
- 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 +1 -2
- package/src/middleware/index.ts +2 -0
- package/src/middleware/remote-auth.test.ts +4 -4
- package/src/middleware/remote-auth.ts +7 -2
- package/src/permissions.ts +70 -0
- package/src/pikku-state.test.ts +0 -26
- package/src/pikku-state.ts +2 -5
- package/src/remote.ts +46 -0
- package/src/schema.ts +1 -0
- package/src/services/credential-service.ts +13 -0
- package/src/services/credential-wire-service.test.ts +174 -0
- package/src/services/credential-wire-service.ts +52 -8
- 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/local-credential-service.ts +22 -0
- 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/pikku-user-id.test.ts +62 -0
- package/src/services/pikku-user-id.ts +17 -0
- package/src/services/typed-credential-service.ts +8 -0
- package/src/services/workflow-service.ts +8 -0
- package/src/testing/service-tests.ts +0 -10
- package/src/types/core.types.ts +16 -2
- package/src/types/state.types.ts +7 -2
- package/src/wirings/ai-agent/ai-agent-prepare.ts +122 -41
- package/src/wirings/ai-agent/ai-agent-registry.ts +3 -3
- package/src/wirings/ai-agent/ai-agent-runner.ts +22 -3
- package/src/wirings/ai-agent/ai-agent-stream.ts +115 -3
- package/src/wirings/ai-agent/ai-agent.types.ts +27 -4
- package/src/wirings/ai-agent/index.ts +1 -0
- package/src/wirings/channel/channel-handler.ts +0 -1
- package/src/wirings/channel/channel-runner.ts +4 -5
- package/src/wirings/cli/cli-runner.test.ts +8 -7
- package/src/wirings/cli/cli-runner.ts +5 -4
- package/src/wirings/cli/command-parser.ts +8 -3
- package/src/wirings/http/http-runner.ts +27 -18
- package/src/wirings/http/http.types.ts +2 -0
- package/src/wirings/mcp/mcp-runner.ts +7 -10
- package/src/wirings/queue/queue-runner.test.ts +5 -11
- package/src/wirings/queue/queue-runner.ts +12 -4
- package/src/wirings/queue/queue.types.ts +6 -0
- package/src/wirings/rpc/rpc-runner.ts +91 -118
- 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-dsl.types.ts +2 -0
- 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 +286 -24
- package/src/wirings/workflow/workflow-queue-workers.ts +85 -0
- package/src/wirings/workflow/workflow.types.ts +18 -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
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
import { readFile, readdir } from 'node:fs/promises'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import type { JSONSchema7 } from 'json-schema'
|
|
4
|
+
import type { HTTPWiringsMeta } from '../wirings/http/http.types.js'
|
|
5
|
+
import type { ChannelsMeta } from '../wirings/channel/channel.types.js'
|
|
6
|
+
import type { ScheduledTasksMeta } from '../wirings/scheduler/scheduler.types.js'
|
|
7
|
+
import type { QueueWorkersMeta } from '../wirings/queue/queue.types.js'
|
|
8
|
+
import type { CLIMeta } from '../wirings/cli/cli.types.js'
|
|
9
|
+
import type {
|
|
10
|
+
MCPResourceMeta,
|
|
11
|
+
MCPToolMeta,
|
|
12
|
+
MCPPromptMeta,
|
|
13
|
+
} from '../wirings/mcp/mcp.types.js'
|
|
14
|
+
import type { WorkflowsMeta } from '../wirings/workflow/workflow.types.js'
|
|
15
|
+
import type {
|
|
16
|
+
TriggerMeta,
|
|
17
|
+
TriggerSourceMeta,
|
|
18
|
+
} from '../wirings/trigger/trigger.types.js'
|
|
19
|
+
import type { SecretDefinitionsMeta } from '../wirings/secret/secret.types.js'
|
|
20
|
+
import type { CredentialDefinitionsMeta } from '../wirings/credential/credential.types.js'
|
|
21
|
+
import type { VariableDefinitionsMeta } from '../wirings/variable/variable.types.js'
|
|
22
|
+
import type {
|
|
23
|
+
FunctionMeta,
|
|
24
|
+
FunctionsMeta,
|
|
25
|
+
MiddlewareMetadata,
|
|
26
|
+
PermissionMetadata,
|
|
27
|
+
} from '../types/core.types.js'
|
|
28
|
+
import type { AIAgentMeta } from '../wirings/ai-agent/ai-agent.types.js'
|
|
29
|
+
|
|
30
|
+
// Re-export core types for consumers
|
|
31
|
+
export type {
|
|
32
|
+
FunctionMeta,
|
|
33
|
+
FunctionsMeta,
|
|
34
|
+
MiddlewareMetadata as MiddlewareMeta,
|
|
35
|
+
PermissionMetadata as PermissionMeta,
|
|
36
|
+
}
|
|
37
|
+
export type AgentsMeta = AIAgentMeta
|
|
38
|
+
export type AgentMeta = AIAgentMeta[string]
|
|
39
|
+
|
|
40
|
+
export interface MCPMeta {
|
|
41
|
+
resources: MCPResourceMeta
|
|
42
|
+
tools: MCPToolMeta
|
|
43
|
+
prompts: MCPPromptMeta
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type RPCMetaRecord = Record<string, string>
|
|
47
|
+
|
|
48
|
+
export interface ServiceMeta {
|
|
49
|
+
name: string
|
|
50
|
+
summary: string
|
|
51
|
+
description: string
|
|
52
|
+
package: string
|
|
53
|
+
path: string
|
|
54
|
+
version: string
|
|
55
|
+
interface: string
|
|
56
|
+
expandedProperties: Record<string, string>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type ServicesMetaRecord = Record<string, ServiceMeta>
|
|
60
|
+
|
|
61
|
+
export interface MiddlewareDefinitionMeta {
|
|
62
|
+
services: { optimized: boolean; services: string[] }
|
|
63
|
+
sourceFile: string
|
|
64
|
+
position: number
|
|
65
|
+
exportedName: string | null
|
|
66
|
+
factory?: boolean
|
|
67
|
+
name?: string
|
|
68
|
+
description?: string
|
|
69
|
+
package?: string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface MiddlewareInstanceMeta {
|
|
73
|
+
definitionId: string
|
|
74
|
+
sourceFile: string
|
|
75
|
+
position: number
|
|
76
|
+
isFactoryCall: boolean
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface GroupMeta {
|
|
80
|
+
exportName: string | null
|
|
81
|
+
sourceFile: string
|
|
82
|
+
position: number
|
|
83
|
+
services: { optimized: boolean; services: string[] }
|
|
84
|
+
count: number
|
|
85
|
+
instanceIds: string[]
|
|
86
|
+
isFactory: boolean
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface MiddlewareGroupsMeta {
|
|
90
|
+
definitions: Record<string, MiddlewareDefinitionMeta>
|
|
91
|
+
instances: Record<string, MiddlewareInstanceMeta>
|
|
92
|
+
httpGroups: Record<string, GroupMeta>
|
|
93
|
+
tagGroups: Record<string, GroupMeta>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface PermissionDefinitionMeta {
|
|
97
|
+
services: { optimized: boolean; services: string[] }
|
|
98
|
+
sourceFile: string
|
|
99
|
+
position: number
|
|
100
|
+
exportedName: string | null
|
|
101
|
+
factory?: boolean
|
|
102
|
+
name?: string
|
|
103
|
+
description?: string
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface PermissionsGroupsMeta {
|
|
107
|
+
definitions: Record<string, PermissionDefinitionMeta>
|
|
108
|
+
httpGroups: Record<string, GroupMeta>
|
|
109
|
+
tagGroups: Record<string, GroupMeta>
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Abstraction over .pikku metadata file access.
|
|
114
|
+
* All paths are relative to the .pikku root directory.
|
|
115
|
+
*
|
|
116
|
+
* Node.js uses LocalMetaService (filesystem).
|
|
117
|
+
* Cloudflare uses an R2/KV implementation.
|
|
118
|
+
*/
|
|
119
|
+
export interface MetaService {
|
|
120
|
+
/** Base path for local filesystem implementations. Undefined for remote/non-local implementations. */
|
|
121
|
+
readonly basePath?: string
|
|
122
|
+
/** Read a file's content by relative path. Returns null if not found. */
|
|
123
|
+
readFile(relativePath: string): Promise<string | null>
|
|
124
|
+
/** List files in a directory by relative path. Returns empty array if not found. */
|
|
125
|
+
readDir(relativePath: string): Promise<string[]>
|
|
126
|
+
|
|
127
|
+
// -- Typed metadata accessors --
|
|
128
|
+
|
|
129
|
+
getHttpMeta(): Promise<HTTPWiringsMeta>
|
|
130
|
+
getChannelsMeta(): Promise<ChannelsMeta>
|
|
131
|
+
getSchedulerMeta(): Promise<ScheduledTasksMeta>
|
|
132
|
+
getQueueMeta(): Promise<QueueWorkersMeta>
|
|
133
|
+
getCliMeta(): Promise<CLIMeta>
|
|
134
|
+
getMcpMeta(): Promise<MCPMeta>
|
|
135
|
+
getRpcMeta(): Promise<RPCMetaRecord>
|
|
136
|
+
getWorkflowMeta(): Promise<WorkflowsMeta>
|
|
137
|
+
getTriggerMeta(): Promise<TriggerMeta>
|
|
138
|
+
getTriggerSourceMeta(): Promise<TriggerSourceMeta>
|
|
139
|
+
getFunctionsMeta(): Promise<FunctionsMeta>
|
|
140
|
+
getMiddlewareGroupsMeta(): Promise<MiddlewareGroupsMeta>
|
|
141
|
+
getPermissionsGroupsMeta(): Promise<PermissionsGroupsMeta>
|
|
142
|
+
getAgentsMeta(): Promise<AgentsMeta>
|
|
143
|
+
getSecretsMeta(): Promise<SecretDefinitionsMeta>
|
|
144
|
+
getCredentialsMeta(): Promise<CredentialDefinitionsMeta>
|
|
145
|
+
getVariablesMeta(): Promise<VariableDefinitionsMeta>
|
|
146
|
+
getServicesMeta(): Promise<ServicesMetaRecord>
|
|
147
|
+
|
|
148
|
+
getSchema(schemaName: string): Promise<JSONSchema7 | null>
|
|
149
|
+
getSchemas(schemaNames: string[]): Promise<Record<string, JSONSchema7 | null>>
|
|
150
|
+
|
|
151
|
+
clearCache(): void
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Node.js filesystem implementation of MetaService.
|
|
156
|
+
* Reads .gen.json files from a local .pikku directory.
|
|
157
|
+
*/
|
|
158
|
+
export class LocalMetaService implements MetaService {
|
|
159
|
+
public readonly basePath: string
|
|
160
|
+
|
|
161
|
+
private httpMetaCache: HTTPWiringsMeta | null = null
|
|
162
|
+
private channelsMetaCache: ChannelsMeta | null = null
|
|
163
|
+
private schedulerMetaCache: ScheduledTasksMeta | null = null
|
|
164
|
+
private queueMetaCache: QueueWorkersMeta | null = null
|
|
165
|
+
private cliMetaCache: CLIMeta | null = null
|
|
166
|
+
private mcpMetaCache: MCPMeta | null = null
|
|
167
|
+
private rpcMetaCache: RPCMetaRecord | null = null
|
|
168
|
+
private workflowMetaCache: WorkflowsMeta | null = null
|
|
169
|
+
private triggerMetaCache: TriggerMeta | null = null
|
|
170
|
+
private triggerSourceMetaCache: TriggerSourceMeta | null = null
|
|
171
|
+
private functionsMetaCache: FunctionsMeta | null = null
|
|
172
|
+
private servicesMetaCache: ServicesMetaRecord | null = null
|
|
173
|
+
private secretsMetaCache: SecretDefinitionsMeta | null = null
|
|
174
|
+
private credentialsMetaCache: CredentialDefinitionsMeta | null = null
|
|
175
|
+
private variablesMetaCache: VariableDefinitionsMeta | null = null
|
|
176
|
+
private middlewareGroupsMetaCache: MiddlewareGroupsMeta | null = null
|
|
177
|
+
private permissionsGroupsMetaCache: PermissionsGroupsMeta | null = null
|
|
178
|
+
private agentsMetaCache: AgentsMeta | null = null
|
|
179
|
+
private schemaCache = new Map<string, JSONSchema7>()
|
|
180
|
+
|
|
181
|
+
constructor(basePath: string) {
|
|
182
|
+
this.basePath = basePath
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async readFile(relativePath: string): Promise<string | null> {
|
|
186
|
+
try {
|
|
187
|
+
return await readFile(join(this.basePath, relativePath), 'utf-8')
|
|
188
|
+
} catch {
|
|
189
|
+
return null
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async readDir(relativePath: string): Promise<string[]> {
|
|
194
|
+
try {
|
|
195
|
+
return await readdir(join(this.basePath, relativePath))
|
|
196
|
+
} catch {
|
|
197
|
+
return []
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
clearCache(): void {
|
|
202
|
+
this.httpMetaCache = null
|
|
203
|
+
this.channelsMetaCache = null
|
|
204
|
+
this.schedulerMetaCache = null
|
|
205
|
+
this.queueMetaCache = null
|
|
206
|
+
this.cliMetaCache = null
|
|
207
|
+
this.mcpMetaCache = null
|
|
208
|
+
this.rpcMetaCache = null
|
|
209
|
+
this.workflowMetaCache = null
|
|
210
|
+
this.triggerMetaCache = null
|
|
211
|
+
this.triggerSourceMetaCache = null
|
|
212
|
+
this.functionsMetaCache = null
|
|
213
|
+
this.servicesMetaCache = null
|
|
214
|
+
this.secretsMetaCache = null
|
|
215
|
+
this.credentialsMetaCache = null
|
|
216
|
+
this.variablesMetaCache = null
|
|
217
|
+
this.middlewareGroupsMetaCache = null
|
|
218
|
+
this.permissionsGroupsMetaCache = null
|
|
219
|
+
this.agentsMetaCache = null
|
|
220
|
+
this.schemaCache.clear()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// -- Private helpers --
|
|
224
|
+
|
|
225
|
+
private async readMetaJson<T>(
|
|
226
|
+
dir: string,
|
|
227
|
+
baseName: string
|
|
228
|
+
): Promise<string | null> {
|
|
229
|
+
const verbose = await this.readFile(`${dir}/${baseName}-verbose.gen.json`)
|
|
230
|
+
if (verbose) return verbose
|
|
231
|
+
const minimal = await this.readFile(`${dir}/${baseName}.gen.json`)
|
|
232
|
+
if (minimal) return minimal
|
|
233
|
+
return null
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// -- Typed metadata accessors --
|
|
237
|
+
|
|
238
|
+
async getHttpMeta(): Promise<HTTPWiringsMeta> {
|
|
239
|
+
if (this.httpMetaCache) return this.httpMetaCache
|
|
240
|
+
|
|
241
|
+
const content = await this.readMetaJson('http', 'pikku-http-wirings-meta')
|
|
242
|
+
this.httpMetaCache = content
|
|
243
|
+
? JSON.parse(content)
|
|
244
|
+
: {
|
|
245
|
+
get: {},
|
|
246
|
+
post: {},
|
|
247
|
+
put: {},
|
|
248
|
+
delete: {},
|
|
249
|
+
patch: {},
|
|
250
|
+
head: {},
|
|
251
|
+
options: {},
|
|
252
|
+
}
|
|
253
|
+
return this.httpMetaCache!
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async getChannelsMeta(): Promise<ChannelsMeta> {
|
|
257
|
+
if (this.channelsMetaCache) return this.channelsMetaCache
|
|
258
|
+
|
|
259
|
+
const content = await this.readMetaJson('channel', 'pikku-channels-meta')
|
|
260
|
+
this.channelsMetaCache = content ? JSON.parse(content) : {}
|
|
261
|
+
return this.channelsMetaCache!
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async getSchedulerMeta(): Promise<ScheduledTasksMeta> {
|
|
265
|
+
if (this.schedulerMetaCache) return this.schedulerMetaCache
|
|
266
|
+
|
|
267
|
+
const content = await this.readMetaJson(
|
|
268
|
+
'scheduler',
|
|
269
|
+
'pikku-schedulers-wirings-meta'
|
|
270
|
+
)
|
|
271
|
+
this.schedulerMetaCache = content ? JSON.parse(content) : {}
|
|
272
|
+
return this.schedulerMetaCache!
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async getQueueMeta(): Promise<QueueWorkersMeta> {
|
|
276
|
+
if (this.queueMetaCache) return this.queueMetaCache
|
|
277
|
+
|
|
278
|
+
const content = await this.readMetaJson(
|
|
279
|
+
'queue',
|
|
280
|
+
'pikku-queue-workers-wirings-meta'
|
|
281
|
+
)
|
|
282
|
+
this.queueMetaCache = content ? JSON.parse(content) : {}
|
|
283
|
+
return this.queueMetaCache!
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async getCliMeta(): Promise<CLIMeta> {
|
|
287
|
+
if (this.cliMetaCache) return this.cliMetaCache
|
|
288
|
+
|
|
289
|
+
const content = await this.readMetaJson('cli', 'pikku-cli-wirings-meta')
|
|
290
|
+
this.cliMetaCache = content
|
|
291
|
+
? JSON.parse(content)
|
|
292
|
+
: { programs: {}, renderers: {} }
|
|
293
|
+
return this.cliMetaCache!
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async getMcpMeta(): Promise<MCPMeta> {
|
|
297
|
+
if (this.mcpMetaCache) return this.mcpMetaCache
|
|
298
|
+
|
|
299
|
+
const content = await this.readMetaJson('mcp', 'pikku-mcp-wirings-meta')
|
|
300
|
+
if (content) {
|
|
301
|
+
const mcpData = JSON.parse(content)
|
|
302
|
+
this.mcpMetaCache = {
|
|
303
|
+
resources: mcpData.resourcesMeta || {},
|
|
304
|
+
tools: mcpData.toolsMeta || {},
|
|
305
|
+
prompts: mcpData.promptsMeta || {},
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
this.mcpMetaCache = { resources: {}, tools: {}, prompts: {} }
|
|
309
|
+
}
|
|
310
|
+
return this.mcpMetaCache!
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async getRpcMeta(): Promise<RPCMetaRecord> {
|
|
314
|
+
if (this.rpcMetaCache) return this.rpcMetaCache
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
const content = await this.readFile('rpc/pikku-rpc-wirings-meta.gen.json')
|
|
318
|
+
this.rpcMetaCache = content ? JSON.parse(content) : {}
|
|
319
|
+
return this.rpcMetaCache!
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error('Error reading RPC wirings metadata:', error)
|
|
322
|
+
this.rpcMetaCache = {}
|
|
323
|
+
return this.rpcMetaCache
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async getWorkflowMeta(): Promise<WorkflowsMeta> {
|
|
328
|
+
if (this.workflowMetaCache) return this.workflowMetaCache
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
const files = await this.readDir('workflow/meta')
|
|
332
|
+
const jsonFiles = files.filter((f) => f.endsWith('.gen.json'))
|
|
333
|
+
const verboseFiles = jsonFiles.filter((f) => f.includes('-verbose'))
|
|
334
|
+
const minimalFiles = jsonFiles.filter((f) => !f.includes('-verbose'))
|
|
335
|
+
const verboseNames = new Set(
|
|
336
|
+
verboseFiles.map((f) => f.replace('-verbose.gen.json', ''))
|
|
337
|
+
)
|
|
338
|
+
const filesToRead = [
|
|
339
|
+
...verboseFiles,
|
|
340
|
+
...minimalFiles.filter(
|
|
341
|
+
(f) => !verboseNames.has(f.replace('.gen.json', ''))
|
|
342
|
+
),
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
const result: WorkflowsMeta = {}
|
|
346
|
+
await Promise.all(
|
|
347
|
+
filesToRead.map(async (file) => {
|
|
348
|
+
const content = await this.readFile(`workflow/meta/${file}`)
|
|
349
|
+
if (content) {
|
|
350
|
+
const meta = JSON.parse(content)
|
|
351
|
+
result[meta.name] = meta
|
|
352
|
+
}
|
|
353
|
+
})
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
this.workflowMetaCache = result
|
|
357
|
+
return this.workflowMetaCache
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.error('Error reading Workflow wirings metadata:', error)
|
|
360
|
+
this.workflowMetaCache = {}
|
|
361
|
+
return this.workflowMetaCache
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async getTriggerMeta(): Promise<TriggerMeta> {
|
|
366
|
+
if (this.triggerMetaCache) return this.triggerMetaCache
|
|
367
|
+
|
|
368
|
+
const content = await this.readMetaJson(
|
|
369
|
+
'trigger',
|
|
370
|
+
'pikku-trigger-wirings-meta'
|
|
371
|
+
)
|
|
372
|
+
this.triggerMetaCache = content ? JSON.parse(content) : {}
|
|
373
|
+
return this.triggerMetaCache!
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
async getTriggerSourceMeta(): Promise<TriggerSourceMeta> {
|
|
377
|
+
if (this.triggerSourceMetaCache) return this.triggerSourceMetaCache
|
|
378
|
+
|
|
379
|
+
const content = await this.readMetaJson(
|
|
380
|
+
'trigger',
|
|
381
|
+
'pikku-trigger-sources-meta'
|
|
382
|
+
)
|
|
383
|
+
this.triggerSourceMetaCache = content ? JSON.parse(content) : {}
|
|
384
|
+
return this.triggerSourceMetaCache!
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
async getFunctionsMeta(): Promise<FunctionsMeta> {
|
|
388
|
+
if (this.functionsMetaCache) return this.functionsMetaCache
|
|
389
|
+
|
|
390
|
+
const content = await this.readMetaJson('function', 'pikku-functions-meta')
|
|
391
|
+
this.functionsMetaCache = content ? JSON.parse(content) : {}
|
|
392
|
+
return this.functionsMetaCache!
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
async getMiddlewareGroupsMeta(): Promise<MiddlewareGroupsMeta> {
|
|
396
|
+
if (this.middlewareGroupsMetaCache) return this.middlewareGroupsMetaCache
|
|
397
|
+
|
|
398
|
+
const content = await this.readMetaJson(
|
|
399
|
+
'middleware',
|
|
400
|
+
'pikku-middleware-groups-meta'
|
|
401
|
+
)
|
|
402
|
+
this.middlewareGroupsMetaCache = content
|
|
403
|
+
? JSON.parse(content)
|
|
404
|
+
: { definitions: {}, instances: {}, httpGroups: {}, tagGroups: {} }
|
|
405
|
+
return this.middlewareGroupsMetaCache!
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async getPermissionsGroupsMeta(): Promise<PermissionsGroupsMeta> {
|
|
409
|
+
if (this.permissionsGroupsMetaCache) return this.permissionsGroupsMetaCache
|
|
410
|
+
|
|
411
|
+
const content = await this.readMetaJson(
|
|
412
|
+
'permissions',
|
|
413
|
+
'pikku-permissions-groups-meta'
|
|
414
|
+
)
|
|
415
|
+
this.permissionsGroupsMetaCache = content
|
|
416
|
+
? JSON.parse(content)
|
|
417
|
+
: { definitions: {}, httpGroups: {}, tagGroups: {} }
|
|
418
|
+
return this.permissionsGroupsMetaCache!
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async getAgentsMeta(): Promise<AgentsMeta> {
|
|
422
|
+
if (this.agentsMetaCache) return this.agentsMetaCache
|
|
423
|
+
|
|
424
|
+
const content = await this.readMetaJson('agent', 'pikku-agent-wirings-meta')
|
|
425
|
+
if (content) {
|
|
426
|
+
const parsed = JSON.parse(content)
|
|
427
|
+
this.agentsMetaCache = parsed.agentsMeta || parsed
|
|
428
|
+
} else {
|
|
429
|
+
this.agentsMetaCache = {}
|
|
430
|
+
}
|
|
431
|
+
return this.agentsMetaCache!
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
async getSecretsMeta(): Promise<SecretDefinitionsMeta> {
|
|
435
|
+
if (this.secretsMetaCache) return this.secretsMetaCache
|
|
436
|
+
|
|
437
|
+
const content = await this.readFile('secrets/pikku-secrets-meta.gen.json')
|
|
438
|
+
this.secretsMetaCache = content ? JSON.parse(content) : {}
|
|
439
|
+
return this.secretsMetaCache!
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async getCredentialsMeta(): Promise<CredentialDefinitionsMeta> {
|
|
443
|
+
if (this.credentialsMetaCache) return this.credentialsMetaCache
|
|
444
|
+
|
|
445
|
+
const content = await this.readFile(
|
|
446
|
+
'credentials/pikku-credentials-meta.gen.json'
|
|
447
|
+
)
|
|
448
|
+
this.credentialsMetaCache = content ? JSON.parse(content) : {}
|
|
449
|
+
return this.credentialsMetaCache!
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
async getVariablesMeta(): Promise<VariableDefinitionsMeta> {
|
|
453
|
+
if (this.variablesMetaCache) return this.variablesMetaCache
|
|
454
|
+
|
|
455
|
+
const content = await this.readFile(
|
|
456
|
+
'variables/pikku-variables-meta.gen.json'
|
|
457
|
+
)
|
|
458
|
+
this.variablesMetaCache = content ? JSON.parse(content) : {}
|
|
459
|
+
return this.variablesMetaCache!
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async getServicesMeta(): Promise<ServicesMetaRecord> {
|
|
463
|
+
if (this.servicesMetaCache) return this.servicesMetaCache
|
|
464
|
+
|
|
465
|
+
try {
|
|
466
|
+
const files = await this.readDir('services')
|
|
467
|
+
const jsonFiles = files.filter((f) => f.endsWith('.gen.json'))
|
|
468
|
+
|
|
469
|
+
const result: ServicesMetaRecord = {}
|
|
470
|
+
await Promise.all(
|
|
471
|
+
jsonFiles.map(async (file) => {
|
|
472
|
+
const content = await this.readFile(`services/${file}`)
|
|
473
|
+
if (content) {
|
|
474
|
+
const meta: ServiceMeta = JSON.parse(content)
|
|
475
|
+
result[meta.name] = meta
|
|
476
|
+
}
|
|
477
|
+
})
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
this.servicesMetaCache = result
|
|
481
|
+
return this.servicesMetaCache
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.error('Error reading Services metadata:', error)
|
|
484
|
+
this.servicesMetaCache = {}
|
|
485
|
+
return this.servicesMetaCache
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
async getSchema(schemaName: string): Promise<JSONSchema7 | null> {
|
|
490
|
+
if (this.schemaCache.has(schemaName)) {
|
|
491
|
+
return this.schemaCache.get(schemaName)!
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (!/^[a-zA-Z0-9_\-\.]+$/.test(schemaName)) {
|
|
495
|
+
return null
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
try {
|
|
499
|
+
const content = await this.readFile(
|
|
500
|
+
`schemas/schemas/${schemaName}.schema.json`
|
|
501
|
+
)
|
|
502
|
+
if (!content) return null
|
|
503
|
+
const schema = JSON.parse(content) as JSONSchema7
|
|
504
|
+
this.schemaCache.set(schemaName, schema)
|
|
505
|
+
return schema
|
|
506
|
+
} catch (error) {
|
|
507
|
+
console.error(`Error reading schema ${schemaName}:`, error)
|
|
508
|
+
return null
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async getSchemas(
|
|
513
|
+
schemaNames: string[]
|
|
514
|
+
): Promise<Record<string, JSONSchema7 | null>> {
|
|
515
|
+
const results: Record<string, JSONSchema7 | null> = {}
|
|
516
|
+
await Promise.all(
|
|
517
|
+
schemaNames.map(async (name) => {
|
|
518
|
+
results[name] = await this.getSchema(name)
|
|
519
|
+
})
|
|
520
|
+
)
|
|
521
|
+
return results
|
|
522
|
+
}
|
|
523
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { defaultPikkuUserIdResolver } from './pikku-user-id.js'
|
|
4
|
+
import type { PikkuWire } from '../types/core.types.js'
|
|
5
|
+
|
|
6
|
+
describe('defaultPikkuUserIdResolver', () => {
|
|
7
|
+
test('should return pikkuUserId from wire', () => {
|
|
8
|
+
const wire: PikkuWire = { pikkuUserId: 'user-1' }
|
|
9
|
+
assert.strictEqual(defaultPikkuUserIdResolver(wire), 'user-1')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should return userId from session', () => {
|
|
13
|
+
const wire: PikkuWire = { session: { userId: 'session-user' } as any }
|
|
14
|
+
assert.strictEqual(defaultPikkuUserIdResolver(wire), 'session-user')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('should prefer pikkuUserId over session', () => {
|
|
18
|
+
const wire: PikkuWire = {
|
|
19
|
+
pikkuUserId: 'explicit',
|
|
20
|
+
session: { userId: 'session-user' } as any,
|
|
21
|
+
}
|
|
22
|
+
assert.strictEqual(defaultPikkuUserIdResolver(wire), 'explicit')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('should return pikkuUserId from queue', () => {
|
|
26
|
+
const wire: PikkuWire = {
|
|
27
|
+
queue: {
|
|
28
|
+
queueName: 'test',
|
|
29
|
+
jobId: '1',
|
|
30
|
+
pikkuUserId: 'queue-user',
|
|
31
|
+
updateProgress: async () => {},
|
|
32
|
+
fail: async () => {},
|
|
33
|
+
discard: async () => {},
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
assert.strictEqual(defaultPikkuUserIdResolver(wire), 'queue-user')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('should return pikkuUserId from workflow', () => {
|
|
40
|
+
const wire: PikkuWire = {
|
|
41
|
+
workflow: {
|
|
42
|
+
name: 'test',
|
|
43
|
+
runId: '1',
|
|
44
|
+
pikkuUserId: 'workflow-user',
|
|
45
|
+
getRun: async () => ({}) as any,
|
|
46
|
+
do: (() => {}) as any,
|
|
47
|
+
sleep: (() => {}) as any,
|
|
48
|
+
} as any,
|
|
49
|
+
}
|
|
50
|
+
assert.strictEqual(defaultPikkuUserIdResolver(wire), 'workflow-user')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('should return undefined when no identity source', () => {
|
|
54
|
+
const wire: PikkuWire = {}
|
|
55
|
+
assert.strictEqual(defaultPikkuUserIdResolver(wire), undefined)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('should ignore non-string session userId', () => {
|
|
59
|
+
const wire: PikkuWire = { session: { userId: 123 } as any }
|
|
60
|
+
assert.strictEqual(defaultPikkuUserIdResolver(wire), undefined)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PikkuWire } from '../types/core.types.js'
|
|
2
|
+
|
|
3
|
+
export type PikkuUserIdResolver = (wire: PikkuWire) => string | undefined
|
|
4
|
+
|
|
5
|
+
export const defaultPikkuUserIdResolver: PikkuUserIdResolver = (wire) => {
|
|
6
|
+
// Explicit pikkuUserId on wire (set by earlier middleware or runner)
|
|
7
|
+
if (wire.pikkuUserId) return wire.pikkuUserId
|
|
8
|
+
// Session userId (from auth middleware — user-defined session shape)
|
|
9
|
+
const session = wire.session as Record<string, unknown> | undefined
|
|
10
|
+
if (session?.userId && typeof session.userId === 'string')
|
|
11
|
+
return session.userId
|
|
12
|
+
// Queue job: carried in job metadata
|
|
13
|
+
if (wire.queue?.pikkuUserId) return wire.queue.pikkuUserId
|
|
14
|
+
// Workflow: carried in run wire metadata
|
|
15
|
+
if (wire.workflow?.pikkuUserId) return wire.workflow.pikkuUserId
|
|
16
|
+
return undefined
|
|
17
|
+
}
|
|
@@ -52,6 +52,14 @@ export class TypedCredentialService<TMap = Record<string, unknown>>
|
|
|
52
52
|
return this.credentials.getAll(userId)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
async getUsersWithCredential(name: string): Promise<string[]> {
|
|
56
|
+
return this.credentials.getUsersWithCredential(name)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async getAllUsers(): Promise<string[]> {
|
|
60
|
+
return this.credentials.getAllUsers()
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
async getAllStatus(userId?: string): Promise<CredentialStatusInfo[]> {
|
|
56
64
|
const results: CredentialStatusInfo[] = []
|
|
57
65
|
|
|
@@ -2,6 +2,7 @@ import type { SerializedError } from '../types/core.types.js'
|
|
|
2
2
|
import type {
|
|
3
3
|
WorkflowRun,
|
|
4
4
|
WorkflowRunWire,
|
|
5
|
+
WorkflowRunStatus,
|
|
5
6
|
StepState,
|
|
6
7
|
WorkflowStatus,
|
|
7
8
|
WorkflowVersionStatus,
|
|
@@ -21,6 +22,7 @@ export interface WorkflowService {
|
|
|
21
22
|
wire: WorkflowRunWire
|
|
22
23
|
): Promise<string>
|
|
23
24
|
getRun(id: string): Promise<WorkflowRun | null>
|
|
25
|
+
getRunStatus(id: string): Promise<WorkflowRunStatus | null>
|
|
24
26
|
getRunHistory(runId: string): Promise<Array<StepState & { stepName: string }>>
|
|
25
27
|
updateRunStatus(
|
|
26
28
|
id: string,
|
|
@@ -40,6 +42,12 @@ export interface WorkflowService {
|
|
|
40
42
|
rpcService: any,
|
|
41
43
|
options?: { inline?: boolean; startNode?: string }
|
|
42
44
|
): Promise<{ runId: string }>
|
|
45
|
+
runToCompletion<I>(
|
|
46
|
+
name: string,
|
|
47
|
+
input: I,
|
|
48
|
+
rpcService: any,
|
|
49
|
+
options?: { pollIntervalMs?: number; wire?: WorkflowRunWire }
|
|
50
|
+
): Promise<unknown>
|
|
43
51
|
runWorkflowJob(runId: string, rpcService: any): Promise<void>
|
|
44
52
|
orchestrateWorkflow(runId: string, rpcService: any): Promise<void>
|
|
45
53
|
executeWorkflowSleepCompleted(runId: string, stepId: string): Promise<void>
|
|
@@ -735,16 +735,6 @@ export function defineServiceTests(config: ServiceTestConfig): void {
|
|
|
735
735
|
endpoint: 'http://localhost:3000',
|
|
736
736
|
functions: ['funcA', 'funcB'],
|
|
737
737
|
})
|
|
738
|
-
|
|
739
|
-
const infos = await service.findFunction('funcA')
|
|
740
|
-
assert.ok(infos.length >= 1)
|
|
741
|
-
assert.equal(infos[0]!.deploymentId, 'deploy-1')
|
|
742
|
-
assert.equal(infos[0]!.endpoint, 'http://localhost:3000')
|
|
743
|
-
})
|
|
744
|
-
|
|
745
|
-
test('findFunction returns empty for unknown function', async () => {
|
|
746
|
-
const infos = await service.findFunction('unknown-func')
|
|
747
|
-
assert.deepEqual(infos, [])
|
|
748
738
|
})
|
|
749
739
|
})
|
|
750
740
|
}
|