@pikku/core 0.12.63 → 0.12.64
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 +147 -0
- package/dist/dev/hot-reload.js +13 -55
- package/dist/dev/module-runner.d.ts +14 -0
- package/dist/dev/module-runner.js +59 -0
- package/dist/dev/reload-meta.d.ts +13 -0
- package/dist/dev/reload-meta.js +22 -0
- package/dist/errors/errors.d.ts +12 -0
- package/dist/errors/errors.js +19 -0
- package/dist/function/function-runner.d.ts +5 -5
- package/dist/function/function-runner.js +39 -111
- package/dist/function/functions.types.d.ts +17 -7
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/middleware/auth-apikey.d.ts +1 -0
- package/dist/middleware/auth-bearer.d.ts +1 -0
- package/dist/middleware/auth-cookie.d.ts +1 -0
- package/dist/middleware/cors.d.ts +1 -0
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/remote-auth.d.ts +1 -0
- package/dist/middleware/telemetry.d.ts +2 -0
- package/dist/middleware/timeout.d.ts +1 -0
- package/dist/permissions.d.ts +32 -25
- package/dist/permissions.js +104 -185
- package/dist/pikku-state.js +0 -2
- package/dist/scopes.d.ts +17 -0
- package/dist/scopes.js +59 -0
- package/dist/services/ai-embedding-service.d.ts +31 -0
- package/dist/services/ai-embedding-service.js +1 -0
- package/dist/services/credential-wire-service.d.ts +3 -1
- package/dist/services/credential-wire-service.js +10 -4
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +2 -0
- package/dist/services/meta-service.d.ts +15 -2
- package/dist/services/meta-service.js +51 -1
- package/dist/services/queue-webhook-service.d.ts +55 -0
- package/dist/services/queue-webhook-service.js +136 -0
- package/dist/services/scope-service.d.ts +67 -0
- package/dist/services/scope-service.js +1 -0
- package/dist/services/typed-secret-service.d.ts +8 -0
- package/dist/services/typed-secret-service.js +39 -4
- package/dist/services/webhook-service.d.ts +140 -0
- package/dist/services/webhook-service.js +44 -0
- package/dist/services/workflow-service.d.ts +7 -0
- package/dist/types/core.types.d.ts +34 -6
- package/dist/types/state.types.d.ts +20 -2
- package/dist/utils/hmac.d.ts +16 -0
- package/dist/utils/hmac.js +26 -0
- package/dist/utils/safe-fetch.d.ts +51 -0
- package/dist/utils/safe-fetch.js +192 -0
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +84 -0
- package/dist/wirings/ai-agent/ai-agent-agui.js +305 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +41 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +146 -6
- package/dist/wirings/ai-agent/ai-agent-runner.js +6 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +61 -10
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +27 -1
- package/dist/wirings/ai-agent/index.d.ts +1 -0
- package/dist/wirings/ai-agent/index.js +1 -0
- package/dist/wirings/ai-agent/voice-input.d.ts +1 -0
- package/dist/wirings/ai-agent/voice-input.js +2 -38
- package/dist/wirings/ai-agent/voice-output.d.ts +1 -0
- package/dist/wirings/channel/channel-common.js +0 -1
- package/dist/wirings/channel/channel-handler.js +1 -4
- package/dist/wirings/channel/channel-middleware-runner.d.ts +12 -0
- package/dist/wirings/channel/channel-middleware-runner.js +34 -19
- package/dist/wirings/channel/channel.types.d.ts +2 -6
- package/dist/wirings/cli/cli-runner.js +0 -2
- package/dist/wirings/cli/cli.types.d.ts +1 -2
- package/dist/wirings/http/http-routes.js +0 -3
- package/dist/wirings/http/http-runner.d.ts +9 -29
- package/dist/wirings/http/http-runner.js +9 -34
- package/dist/wirings/http/http.types.d.ts +1 -9
- package/dist/wirings/mcp/mcp-runner.js +0 -2
- package/dist/wirings/mcp/mcp.types.d.ts +5 -11
- package/dist/wirings/oauth2/index.d.ts +0 -3
- package/dist/wirings/oauth2/index.js +1 -2
- package/dist/wirings/rpc/addon-runner.d.ts +28 -0
- package/dist/wirings/rpc/addon-runner.js +173 -0
- package/dist/wirings/rpc/index.d.ts +5 -1
- package/dist/wirings/rpc/index.js +3 -1
- package/dist/wirings/rpc/remote-addon-auth.d.ts +26 -0
- package/dist/wirings/rpc/remote-addon-auth.js +43 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +19 -0
- package/dist/wirings/rpc/rpc-runner.js +109 -3
- package/dist/wirings/rpc/rpc-types.d.ts +15 -1
- package/dist/wirings/rpc/wire-addon.js +9 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +47 -0
- package/dist/wirings/rpc/wire-remote-addon.js +19 -0
- package/dist/wirings/scope/index.d.ts +3 -0
- package/dist/wirings/scope/index.js +2 -0
- package/dist/wirings/scope/scope.types.d.ts +39 -0
- package/dist/wirings/scope/scope.types.js +1 -0
- package/dist/wirings/scope/validate-scope-definitions.d.ts +16 -0
- package/dist/wirings/scope/validate-scope-definitions.js +76 -0
- package/dist/wirings/scope/wire-scope.d.ts +33 -0
- package/dist/wirings/scope/wire-scope.js +32 -0
- package/dist/wirings/workflow/dsl/index.d.ts +1 -1
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +53 -1
- package/dist/wirings/workflow/graph/graph-node.d.ts +2 -0
- package/dist/wirings/workflow/graph/graph-runner.js +3 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +6 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.js +1 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +5 -0
- package/dist/wirings/workflow/index.d.ts +2 -2
- package/dist/wirings/workflow/index.js +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +51 -1
- package/dist/wirings/workflow/pikku-workflow-service.js +171 -0
- package/dist/wirings/workflow/workflow.types.d.ts +1 -1
- package/package.json +5 -1
- package/run-tests.sh +1 -0
- package/src/dev/hot-reload.ts +13 -68
- package/src/dev/module-runner.test.ts +169 -0
- package/src/dev/module-runner.ts +103 -0
- package/src/dev/reload-meta.test.ts +31 -2
- package/src/dev/reload-meta.ts +26 -0
- package/src/errors/errors.ts +24 -0
- package/src/function/function-runner.test.ts +276 -142
- package/src/function/function-runner.ts +52 -145
- package/src/function/functions.types.ts +28 -38
- package/src/index.ts +8 -6
- package/src/middleware/index.ts +1 -5
- package/src/permissions.test.ts +153 -372
- package/src/permissions.ts +139 -259
- package/src/pikku-state.ts +0 -2
- package/src/scopes.test.ts +167 -0
- package/src/scopes.ts +69 -0
- package/src/services/ai-embedding-service.ts +31 -0
- package/src/services/credential-wire-service.ts +10 -4
- package/src/services/index.ts +20 -0
- package/src/services/meta-service.ts +68 -3
- package/src/services/queue-webhook-service.test.ts +408 -0
- package/src/services/queue-webhook-service.ts +182 -0
- package/src/services/scope-service.ts +75 -0
- package/src/services/typed-secret-service.test.ts +35 -0
- package/src/services/typed-secret-service.ts +39 -4
- package/src/services/webhook-service.ts +180 -0
- package/src/services/workflow-service.ts +7 -0
- package/src/types/core.types.ts +42 -14
- package/src/types/state.types.ts +23 -3
- package/src/utils/hmac.ts +27 -0
- package/src/utils/safe-fetch.test.ts +373 -0
- package/src/utils/safe-fetch.ts +213 -0
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +1127 -0
- package/src/wirings/ai-agent/ai-agent-agui.ts +386 -0
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +308 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +192 -8
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +48 -1
- package/src/wirings/ai-agent/ai-agent-runner.ts +21 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +198 -10
- package/src/wirings/ai-agent/ai-agent-stream.ts +84 -10
- package/src/wirings/ai-agent/ai-agent.types.ts +28 -0
- package/src/wirings/ai-agent/index.ts +1 -0
- package/src/wirings/ai-agent/voice-input.ts +6 -35
- package/src/wirings/channel/channel-common.ts +0 -1
- package/src/wirings/channel/channel-handler.ts +1 -9
- package/src/wirings/channel/channel-middleware-runner.test.ts +28 -2
- package/src/wirings/channel/channel-middleware-runner.ts +39 -27
- package/src/wirings/channel/channel.types.ts +0 -6
- package/src/wirings/cli/cli-runner.ts +0 -2
- package/src/wirings/cli/cli.types.ts +0 -2
- package/src/wirings/http/http-routes.ts +0 -3
- package/src/wirings/http/http-runner.test.ts +1 -11
- package/src/wirings/http/http-runner.ts +16 -39
- package/src/wirings/http/http.types.ts +1 -10
- package/src/wirings/mcp/mcp-runner.ts +0 -2
- package/src/wirings/mcp/mcp.types.ts +3 -11
- package/src/wirings/oauth2/index.ts +0 -3
- package/src/wirings/rpc/addon-runner.ts +233 -0
- package/src/wirings/rpc/index.ts +17 -1
- package/src/wirings/rpc/remote-addon-auth.ts +69 -0
- package/src/wirings/rpc/rpc-runner.test.ts +319 -16
- package/src/wirings/rpc/rpc-runner.ts +155 -3
- package/src/wirings/rpc/rpc-types.ts +16 -5
- package/src/wirings/rpc/wire-addon.test.ts +6 -3
- package/src/wirings/rpc/wire-addon.ts +9 -0
- package/src/wirings/rpc/wire-remote-addon.ts +57 -0
- package/src/wirings/scope/index.ts +14 -0
- package/src/wirings/scope/scope.test.ts +135 -0
- package/src/wirings/scope/scope.types.ts +44 -0
- package/src/wirings/scope/validate-scope-definitions.ts +110 -0
- package/src/wirings/scope/wire-scope.ts +34 -0
- package/src/wirings/workflow/dsl/index.ts +4 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +61 -0
- package/src/wirings/workflow/graph/graph-node.ts +2 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +58 -0
- package/src/wirings/workflow/graph/graph-runner.ts +3 -0
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +7 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +5 -0
- package/src/wirings/workflow/index.ts +5 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +341 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +236 -0
- package/src/wirings/workflow/workflow-step-session.test.ts +21 -5
- package/src/wirings/workflow/workflow.types.ts +4 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/wirings/oauth2/oauth2-client.test.ts +0 -930
- package/src/wirings/oauth2/oauth2-client.ts +0 -331
- package/src/wirings/oauth2/oauth2-routes.ts +0 -234
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SerializeOptions } from 'cookie';
|
|
2
2
|
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
3
|
import type { CorePikkuMiddleware, CommonWireMeta } from '../../types/core.types.js';
|
|
4
|
-
import type { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission,
|
|
4
|
+
import type { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission, CorePikkuFunctionConfig } from '../../function/functions.types.js';
|
|
5
5
|
type ExtractHTTPWiringParams<S extends string> = S extends `${string}:${infer Param}/${infer Rest}` ? Param | ExtractHTTPWiringParams<`/${Rest}`> : S extends `${string}:${infer Param}` ? Param : never;
|
|
6
6
|
export type AssertHTTPWiringParams<In, HTTPWiring extends string> = ExtractHTTPWiringParams<HTTPWiring> extends keyof In ? unknown : [
|
|
7
7
|
'Error: HTTPWiring parameters',
|
|
@@ -75,7 +75,6 @@ export type CoreHTTPFunctionWiring<In, Out, R extends string, PikkuFunction exte
|
|
|
75
75
|
route: R;
|
|
76
76
|
method: HTTPMethod;
|
|
77
77
|
func: CorePikkuFunctionConfig<PikkuFunction, PikkuPermission, PikkuMiddleware>;
|
|
78
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
79
78
|
auth?: true;
|
|
80
79
|
middleware?: PikkuMiddleware[];
|
|
81
80
|
sse?: undefined;
|
|
@@ -83,7 +82,6 @@ export type CoreHTTPFunctionWiring<In, Out, R extends string, PikkuFunction exte
|
|
|
83
82
|
route: R;
|
|
84
83
|
method: HTTPMethod;
|
|
85
84
|
func: CorePikkuFunctionConfig<PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware>;
|
|
86
|
-
permissions?: undefined;
|
|
87
85
|
auth?: false;
|
|
88
86
|
middleware?: PikkuMiddleware[];
|
|
89
87
|
sse?: undefined;
|
|
@@ -91,7 +89,6 @@ export type CoreHTTPFunctionWiring<In, Out, R extends string, PikkuFunction exte
|
|
|
91
89
|
route: R;
|
|
92
90
|
method: 'get';
|
|
93
91
|
func: CorePikkuFunctionConfig<PikkuFunction, PikkuPermission, PikkuMiddleware>;
|
|
94
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
95
92
|
auth?: true;
|
|
96
93
|
middleware?: PikkuMiddleware[];
|
|
97
94
|
sse?: boolean;
|
|
@@ -99,7 +96,6 @@ export type CoreHTTPFunctionWiring<In, Out, R extends string, PikkuFunction exte
|
|
|
99
96
|
route: R;
|
|
100
97
|
method: 'get';
|
|
101
98
|
func: CorePikkuFunctionConfig<PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware>;
|
|
102
|
-
permissions?: undefined;
|
|
103
99
|
auth?: false;
|
|
104
100
|
middleware?: PikkuMiddleware[];
|
|
105
101
|
sse?: boolean;
|
|
@@ -107,7 +103,6 @@ export type CoreHTTPFunctionWiring<In, Out, R extends string, PikkuFunction exte
|
|
|
107
103
|
route: R;
|
|
108
104
|
method: 'post';
|
|
109
105
|
func: CorePikkuFunctionConfig<PikkuFunction, PikkuPermission, PikkuMiddleware>;
|
|
110
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
111
106
|
auth?: true;
|
|
112
107
|
middleware?: PikkuMiddleware[];
|
|
113
108
|
query?: Array<keyof In>;
|
|
@@ -116,7 +111,6 @@ export type CoreHTTPFunctionWiring<In, Out, R extends string, PikkuFunction exte
|
|
|
116
111
|
route: R;
|
|
117
112
|
method: 'post';
|
|
118
113
|
func: CorePikkuFunctionConfig<PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware>;
|
|
119
|
-
permissions?: undefined;
|
|
120
114
|
auth?: false;
|
|
121
115
|
middleware?: PikkuMiddleware[];
|
|
122
116
|
query?: Array<keyof In>;
|
|
@@ -188,7 +182,6 @@ export type HTTPRouteConfig<PikkuFunction extends CorePikkuFunction<any, any, an
|
|
|
188
182
|
route: string;
|
|
189
183
|
func: CorePikkuFunctionConfig<PikkuFunction, PikkuPermission, PikkuMiddleware>;
|
|
190
184
|
auth?: boolean;
|
|
191
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
192
185
|
middleware?: PikkuMiddleware[];
|
|
193
186
|
sse?: boolean;
|
|
194
187
|
};
|
|
@@ -200,7 +193,6 @@ export type HTTPRoutesGroupConfig<PikkuPermission extends CorePikkuPermission<an
|
|
|
200
193
|
tags?: string[];
|
|
201
194
|
auth?: boolean;
|
|
202
195
|
middleware?: PikkuMiddleware[];
|
|
203
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
204
196
|
};
|
|
205
197
|
/**
|
|
206
198
|
* Nested route map - allows hierarchical organization
|
|
@@ -134,8 +134,6 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncId, { mcp: mcp
|
|
|
134
134
|
data: () => request.params,
|
|
135
135
|
inheritedMiddleware: meta?.middleware,
|
|
136
136
|
wireMiddleware: mcp?.middleware,
|
|
137
|
-
inheritedPermissions: meta?.permissions,
|
|
138
|
-
wirePermissions: mcp?.permissions,
|
|
139
137
|
tags: mcp?.tags,
|
|
140
138
|
wire,
|
|
141
139
|
sessionService: mcpSessionService,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { CorePikkuMiddleware, MiddlewareMetadata
|
|
1
|
+
import type { CorePikkuFunctionConfig, CorePikkuFunctionSessionless, CorePikkuPermission } from '../../function/functions.types.js';
|
|
2
|
+
import type { CorePikkuMiddleware, MiddlewareMetadata } from '../../types/core.types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Extract URI parameters from MCP resource URI template.
|
|
5
5
|
* E.g., "user/{userId}/post/{postId}" => "userId" | "postId"
|
|
@@ -25,27 +25,25 @@ export type PikkuMCP<Tools extends string = any> = {
|
|
|
25
25
|
/**
|
|
26
26
|
* Represents metadata for MCP resources, including name, description, and documentation.
|
|
27
27
|
*/
|
|
28
|
-
export type MCPResourceMeta = Record<string, Omit<CoreMCPResource, 'func' | 'middleware'
|
|
28
|
+
export type MCPResourceMeta = Record<string, Omit<CoreMCPResource, 'func' | 'middleware'> & {
|
|
29
29
|
pikkuFuncId: string;
|
|
30
30
|
inputSchema: string | null;
|
|
31
31
|
outputSchema: string | null;
|
|
32
32
|
middleware?: MiddlewareMetadata[];
|
|
33
|
-
permissions?: PermissionMetadata[];
|
|
34
33
|
}>;
|
|
35
34
|
/**
|
|
36
35
|
* Represents metadata for MCP tools, including name, description, and documentation.
|
|
37
36
|
*/
|
|
38
|
-
export type MCPToolMeta = Record<string, Omit<CoreMCPTool, 'func' | 'middleware'
|
|
37
|
+
export type MCPToolMeta = Record<string, Omit<CoreMCPTool, 'func' | 'middleware'> & {
|
|
39
38
|
pikkuFuncId: string;
|
|
40
39
|
inputSchema: string | null;
|
|
41
40
|
outputSchema: string | null;
|
|
42
41
|
middleware?: MiddlewareMetadata[];
|
|
43
|
-
permissions?: PermissionMetadata[];
|
|
44
42
|
}>;
|
|
45
43
|
/**
|
|
46
44
|
* Represents metadata for MCP prompts, including name, description, and arguments.
|
|
47
45
|
*/
|
|
48
|
-
export type MCPPromptMeta = Record<string, Omit<CoreMCPPrompt, 'func' | 'middleware'
|
|
46
|
+
export type MCPPromptMeta = Record<string, Omit<CoreMCPPrompt, 'func' | 'middleware'> & {
|
|
49
47
|
pikkuFuncId: string;
|
|
50
48
|
inputSchema: string | null;
|
|
51
49
|
outputSchema: string | null;
|
|
@@ -55,7 +53,6 @@ export type MCPPromptMeta = Record<string, Omit<CoreMCPPrompt, 'func' | 'middlew
|
|
|
55
53
|
required: boolean;
|
|
56
54
|
}>;
|
|
57
55
|
middleware?: MiddlewareMetadata[];
|
|
58
|
-
permissions?: PermissionMetadata[];
|
|
59
56
|
}>;
|
|
60
57
|
/**
|
|
61
58
|
* Represents an MCP resource with specific properties.
|
|
@@ -72,7 +69,6 @@ export type CoreMCPResource<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePi
|
|
|
72
69
|
func: PikkuFunctionConfig;
|
|
73
70
|
tags?: string[];
|
|
74
71
|
middleware?: PikkuMiddleware[];
|
|
75
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
76
72
|
};
|
|
77
73
|
/**
|
|
78
74
|
* Represents an MCP tool with specific properties.
|
|
@@ -87,7 +83,6 @@ export type CoreMCPTool<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikkuF
|
|
|
87
83
|
tags?: string[];
|
|
88
84
|
streaming?: boolean;
|
|
89
85
|
middleware?: PikkuMiddleware[];
|
|
90
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
91
86
|
};
|
|
92
87
|
/**
|
|
93
88
|
* Represents an MCP prompt with specific properties.
|
|
@@ -100,7 +95,6 @@ export type CoreMCPPrompt<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikk
|
|
|
100
95
|
func: PikkuFunctionConfig;
|
|
101
96
|
tags?: string[];
|
|
102
97
|
middleware?: PikkuMiddleware[];
|
|
103
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
104
98
|
};
|
|
105
99
|
export type JsonRpcRequest = {
|
|
106
100
|
jsonrpc: string;
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { createOAuth2Handler } from './oauth2-routes.js';
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CoreSingletonServices } from '../../types/core.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A single wired addon instance: a namespace (wireAddon `name`) plus the
|
|
4
|
+
* per-instance name-aliases that remap the logical names the addon reads to
|
|
5
|
+
* the actual project secret/variable/credential names.
|
|
6
|
+
*/
|
|
7
|
+
export type AddonInstance = {
|
|
8
|
+
namespace: string;
|
|
9
|
+
secretOverrides?: Record<string, string>;
|
|
10
|
+
variableOverrides?: Record<string, string>;
|
|
11
|
+
credentialOverrides?: Record<string, string>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Get or create singleton services for an addon instance.
|
|
15
|
+
* Services are cached in pikkuState to avoid recreation on each call.
|
|
16
|
+
*
|
|
17
|
+
* @param packageName - The addon package name
|
|
18
|
+
* @param parentServices - The parent/caller's singleton services (used as base)
|
|
19
|
+
* @param addonInstance - The wired instance whose overrides shape the services
|
|
20
|
+
* @returns The instance's singleton services
|
|
21
|
+
*/
|
|
22
|
+
export declare const getOrCreatePackageSingletonServices: (packageName: string, parentServices: CoreSingletonServices, addonInstance?: AddonInstance) => Promise<CoreSingletonServices>;
|
|
23
|
+
/**
|
|
24
|
+
* Build the addon instance descriptor (namespace + per-instance overrides) for
|
|
25
|
+
* a bare intra-addon call, using the namespace currently executing on the wire.
|
|
26
|
+
* Returns undefined unless that namespace maps to the resolved package.
|
|
27
|
+
*/
|
|
28
|
+
export declare const addonInstanceForNamespace: (namespace: string | undefined, expectedPackage: string) => AddonInstance | undefined;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { pikkuState } from '../../pikku-state.js';
|
|
2
|
+
/**
|
|
3
|
+
* Wrap a SecretService so that the logical secret names an addon reads are
|
|
4
|
+
* remapped to the actual project secret names via the instance's overrides.
|
|
5
|
+
*/
|
|
6
|
+
const aliasSecretService = (secrets, overrides) => {
|
|
7
|
+
const map = (key) => overrides[key] ?? key;
|
|
8
|
+
return {
|
|
9
|
+
getSecret: (key) => secrets.getSecret(map(key)),
|
|
10
|
+
hasSecret: (key) => secrets.hasSecret(map(key)),
|
|
11
|
+
setSecret: (key, value) => secrets.setSecret(map(key), value),
|
|
12
|
+
deleteSecret: (key) => secrets.deleteSecret(map(key)),
|
|
13
|
+
getSecrets: async (keys) => {
|
|
14
|
+
const result = await secrets.getSecrets(keys.map(map));
|
|
15
|
+
const out = {};
|
|
16
|
+
for (const logical of keys) {
|
|
17
|
+
const real = map(logical);
|
|
18
|
+
if (real in result)
|
|
19
|
+
out[logical] = result[real];
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Wrap a VariablesService so that the logical variable names an addon reads
|
|
27
|
+
* are remapped to the actual project variable names via the instance's overrides.
|
|
28
|
+
*/
|
|
29
|
+
const aliasVariablesService = (variables, overrides) => {
|
|
30
|
+
const map = (name) => overrides[name] ?? name;
|
|
31
|
+
return {
|
|
32
|
+
get: (name) => variables.get(map(name)),
|
|
33
|
+
getVariables: (names) => {
|
|
34
|
+
const result = variables.getVariables(names.map(map));
|
|
35
|
+
const remap = (r) => {
|
|
36
|
+
const out = {};
|
|
37
|
+
for (const logical of names) {
|
|
38
|
+
const real = map(logical);
|
|
39
|
+
if (real in r)
|
|
40
|
+
out[logical] = r[real];
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
};
|
|
44
|
+
return result instanceof Promise
|
|
45
|
+
? result.then(remap)
|
|
46
|
+
: remap(result);
|
|
47
|
+
},
|
|
48
|
+
getAll: () => variables.getAll(),
|
|
49
|
+
set: (name, value) => variables.set(map(name), value),
|
|
50
|
+
has: (name) => variables.has(map(name)),
|
|
51
|
+
delete: (name) => variables.delete(map(name)),
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Find the consumer-defined namespace (from wireAddon) for a given addon package.
|
|
56
|
+
* Returns null if the package isn't registered as an addon.
|
|
57
|
+
*/
|
|
58
|
+
const findAddonNamespaceForPackage = (packageName) => {
|
|
59
|
+
const addons = pikkuState(null, 'addons', 'packages');
|
|
60
|
+
if (!addons)
|
|
61
|
+
return null;
|
|
62
|
+
for (const [namespace, cfg] of addons.entries()) {
|
|
63
|
+
if (cfg?.package === packageName)
|
|
64
|
+
return namespace;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Wrap a workflow service so that bare workflow names passed from inside an
|
|
70
|
+
* addon function are auto-prefixed with the addon's consumer-facing namespace.
|
|
71
|
+
* Without this, `runToCompletion('myWorkflow')` from inside an addon misses
|
|
72
|
+
* the workflow registered under the addon's package scope and throws
|
|
73
|
+
* WorkflowNotFoundError — forcing addons to hardcode their consumer-defined
|
|
74
|
+
* namespace, which couples the addon to its caller.
|
|
75
|
+
*
|
|
76
|
+
* Explicit `'ns:name'` and bare names that already exist in root meta are
|
|
77
|
+
* unaffected; only bare names that would otherwise miss resolution get
|
|
78
|
+
* prefixed.
|
|
79
|
+
*/
|
|
80
|
+
const wrapWorkflowServiceForPackage = (service, packageName, namespace) => {
|
|
81
|
+
return new Proxy(service, {
|
|
82
|
+
get(target, prop, receiver) {
|
|
83
|
+
if (prop === 'startWorkflow' || prop === 'runToCompletion') {
|
|
84
|
+
const original = Reflect.get(target, prop, receiver);
|
|
85
|
+
return function (name, ...rest) {
|
|
86
|
+
if (typeof name === 'string' && !name.includes(':')) {
|
|
87
|
+
// Prefer the known instance namespace; fall back to the
|
|
88
|
+
// package's sole namespace when invoked without an instance.
|
|
89
|
+
const ns = namespace ?? findAddonNamespaceForPackage(packageName);
|
|
90
|
+
if (ns) {
|
|
91
|
+
name = `${ns}:${name}`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return original.call(this, name, ...rest);
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return Reflect.get(target, prop, receiver);
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Get or create singleton services for an addon instance.
|
|
103
|
+
* Services are cached in pikkuState to avoid recreation on each call.
|
|
104
|
+
*
|
|
105
|
+
* @param packageName - The addon package name
|
|
106
|
+
* @param parentServices - The parent/caller's singleton services (used as base)
|
|
107
|
+
* @param addonInstance - The wired instance whose overrides shape the services
|
|
108
|
+
* @returns The instance's singleton services
|
|
109
|
+
*/
|
|
110
|
+
export const getOrCreatePackageSingletonServices = async (packageName, parentServices, addonInstance) => {
|
|
111
|
+
// Cache per instance (namespace), not per package, so two instances of one
|
|
112
|
+
// package get separate services built with their own overrides. A bare
|
|
113
|
+
// package-scoped call (no instance) falls back to per-package caching.
|
|
114
|
+
const cacheKey = addonInstance?.namespace ?? packageName;
|
|
115
|
+
const cachedServices = pikkuState(cacheKey, 'package', 'singletonServices');
|
|
116
|
+
if (cachedServices) {
|
|
117
|
+
return cachedServices;
|
|
118
|
+
}
|
|
119
|
+
const factories = pikkuState(packageName, 'package', 'factories');
|
|
120
|
+
if (!factories || !factories.createSingletonServices) {
|
|
121
|
+
// No factories registered, use parent services
|
|
122
|
+
return parentServices;
|
|
123
|
+
}
|
|
124
|
+
// Apply this instance's secret/variable overrides by aliasing the resolver
|
|
125
|
+
// services the addon reads from, so its createSingletonServices resolves
|
|
126
|
+
// instance-specific secrets/variables.
|
|
127
|
+
let existingServices = parentServices;
|
|
128
|
+
if (addonInstance?.secretOverrides && parentServices.secrets) {
|
|
129
|
+
existingServices = {
|
|
130
|
+
...existingServices,
|
|
131
|
+
secrets: aliasSecretService(parentServices.secrets, addonInstance.secretOverrides),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (addonInstance?.variableOverrides && parentServices.variables) {
|
|
135
|
+
existingServices = {
|
|
136
|
+
...existingServices,
|
|
137
|
+
variables: aliasVariablesService(parentServices.variables, addonInstance.variableOverrides),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Create config for the package (use parent config if no factory)
|
|
141
|
+
let config = existingServices.config;
|
|
142
|
+
if (factories.createConfig) {
|
|
143
|
+
config = await factories.createConfig(existingServices.variables);
|
|
144
|
+
}
|
|
145
|
+
// Create singleton services for the package, passing parent services as existing
|
|
146
|
+
const packageServices = await factories.createSingletonServices(config, existingServices);
|
|
147
|
+
// Wrap workflowService so that bare names used inside the addon's functions
|
|
148
|
+
// resolve to workflows registered under the addon's package scope.
|
|
149
|
+
if (packageServices.workflowService &&
|
|
150
|
+
typeof packageServices.workflowService === 'object') {
|
|
151
|
+
packageServices.workflowService = wrapWorkflowServiceForPackage(packageServices.workflowService, packageName, addonInstance?.namespace ?? null);
|
|
152
|
+
}
|
|
153
|
+
pikkuState(cacheKey, 'package', 'singletonServices', packageServices);
|
|
154
|
+
return packageServices;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Build the addon instance descriptor (namespace + per-instance overrides) for
|
|
158
|
+
* a bare intra-addon call, using the namespace currently executing on the wire.
|
|
159
|
+
* Returns undefined unless that namespace maps to the resolved package.
|
|
160
|
+
*/
|
|
161
|
+
export const addonInstanceForNamespace = (namespace, expectedPackage) => {
|
|
162
|
+
if (!namespace)
|
|
163
|
+
return undefined;
|
|
164
|
+
const cfg = pikkuState(null, 'addons', 'packages').get(namespace);
|
|
165
|
+
if (!cfg || cfg.package !== expectedPackage)
|
|
166
|
+
return undefined;
|
|
167
|
+
return {
|
|
168
|
+
namespace,
|
|
169
|
+
secretOverrides: cfg.secretOverrides,
|
|
170
|
+
variableOverrides: cfg.variableOverrides,
|
|
171
|
+
credentialOverrides: cfg.credentialOverrides,
|
|
172
|
+
};
|
|
173
|
+
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export { PikkuRPCService, rpcService, RPCNotFoundError } from './rpc-runner.js';
|
|
1
|
+
export { PikkuRPCService, rpcService, RPCNotFoundError, RemoteAddonConfigError, RemoteAddonRequestError, } from './rpc-runner.js';
|
|
2
|
+
export { resolveRemoteAddonToken, RemoteAddonAuthError, } from './remote-addon-auth.js';
|
|
3
|
+
export type { RemoteAddonAuthBinding } from './remote-addon-auth.js';
|
|
2
4
|
export type { PikkuRPC, RPCMeta } from './rpc-types.js';
|
|
3
5
|
export { wireAddon } from './wire-addon.js';
|
|
4
6
|
export type { WireAddonConfig } from './wire-addon.js';
|
|
7
|
+
export { wireRemoteAddon } from './wire-remote-addon.js';
|
|
8
|
+
export type { WireRemoteAddonConfig, RemoteAddonAuth, } from './wire-remote-addon.js';
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
export { PikkuRPCService, rpcService, RPCNotFoundError } from './rpc-runner.js';
|
|
1
|
+
export { PikkuRPCService, rpcService, RPCNotFoundError, RemoteAddonConfigError, RemoteAddonRequestError, } from './rpc-runner.js';
|
|
2
|
+
export { resolveRemoteAddonToken, RemoteAddonAuthError, } from './remote-addon-auth.js';
|
|
2
3
|
export { wireAddon } from './wire-addon.js';
|
|
4
|
+
export { wireRemoteAddon } from './wire-remote-addon.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CoreServices, PikkuRawWire } from '../../types/core.types.js';
|
|
2
|
+
import { PikkuError } from '../../errors/error-handler.js';
|
|
3
|
+
/**
|
|
4
|
+
* How a `wireRemoteAddon` consumer supplies the token the hosted addon expects.
|
|
5
|
+
* This is a CLIENT authenticating to a hosted library — not the trusted mesh.
|
|
6
|
+
*/
|
|
7
|
+
export type RemoteAddonAuthBinding = {
|
|
8
|
+
credentialId: string;
|
|
9
|
+
} | {
|
|
10
|
+
secretId: string;
|
|
11
|
+
} | {
|
|
12
|
+
resolve: (services: CoreServices, wire: PikkuRawWire) => string | Promise<string>;
|
|
13
|
+
};
|
|
14
|
+
/** The addon's auth was bound but the source produced no token — fail closed. */
|
|
15
|
+
export declare class RemoteAddonAuthError extends PikkuError {
|
|
16
|
+
readonly namespace: string;
|
|
17
|
+
constructor(namespace: string, detail: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the bearer token for a remote addon call from the consumer's bound
|
|
21
|
+
* source. Returns `null` only when no auth is bound (a public surface).
|
|
22
|
+
*
|
|
23
|
+
* Security: the resolved token is never logged or traced; per-user credentials
|
|
24
|
+
* are read via the wire (scoped to `pikkuUserId`); an empty result fails closed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveRemoteAddonToken(auth: RemoteAddonAuthBinding | undefined, services: CoreServices, wire: PikkuRawWire, namespace: string): Promise<string | null>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { PikkuError, addError } from '../../errors/error-handler.js';
|
|
2
|
+
/** The addon's auth was bound but the source produced no token — fail closed. */
|
|
3
|
+
export class RemoteAddonAuthError extends PikkuError {
|
|
4
|
+
namespace;
|
|
5
|
+
constructor(namespace, detail) {
|
|
6
|
+
super(`Remote addon '${namespace}' auth could not be resolved: ${detail}`);
|
|
7
|
+
this.namespace = namespace;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
addError(RemoteAddonAuthError, {
|
|
11
|
+
status: 401,
|
|
12
|
+
message: 'Remote addon authentication could not be resolved.',
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the bearer token for a remote addon call from the consumer's bound
|
|
16
|
+
* source. Returns `null` only when no auth is bound (a public surface).
|
|
17
|
+
*
|
|
18
|
+
* Security: the resolved token is never logged or traced; per-user credentials
|
|
19
|
+
* are read via the wire (scoped to `pikkuUserId`); an empty result fails closed.
|
|
20
|
+
*/
|
|
21
|
+
export async function resolveRemoteAddonToken(auth, services, wire, namespace) {
|
|
22
|
+
if (!auth) {
|
|
23
|
+
// No auth bound → the addon declares its remote surface public.
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
let token;
|
|
27
|
+
if ('credentialId' in auth) {
|
|
28
|
+
if (typeof wire.getCredential !== 'function') {
|
|
29
|
+
throw new RemoteAddonAuthError(namespace, `credentialId '${auth.credentialId}' requires a wire with credential access`);
|
|
30
|
+
}
|
|
31
|
+
token = await wire.getCredential(auth.credentialId);
|
|
32
|
+
}
|
|
33
|
+
else if ('secretId' in auth) {
|
|
34
|
+
token = await services.secrets.getSecret(auth.secretId);
|
|
35
|
+
}
|
|
36
|
+
else if (typeof auth.resolve === 'function') {
|
|
37
|
+
token = await auth.resolve(services, wire);
|
|
38
|
+
}
|
|
39
|
+
if (token === null || token === undefined || token === '') {
|
|
40
|
+
throw new RemoteAddonAuthError(namespace, 'resolved token was empty');
|
|
41
|
+
}
|
|
42
|
+
return String(token);
|
|
43
|
+
}
|
|
@@ -7,6 +7,15 @@ export declare class RPCNotFoundError extends PikkuError {
|
|
|
7
7
|
readonly rpcName: string;
|
|
8
8
|
constructor(rpcName: string);
|
|
9
9
|
}
|
|
10
|
+
/** A `wireRemoteAddon` namespace is missing a usable `serverUrl`. */
|
|
11
|
+
export declare class RemoteAddonConfigError extends PikkuError {
|
|
12
|
+
constructor(namespace: string, detail: string);
|
|
13
|
+
}
|
|
14
|
+
/** The hosted addon returned a non-2xx response for a remote RPC. */
|
|
15
|
+
export declare class RemoteAddonRequestError extends PikkuError {
|
|
16
|
+
readonly httpStatus: number;
|
|
17
|
+
constructor(namespace: string, fnName: string, status: number, detail: string);
|
|
18
|
+
}
|
|
10
19
|
import type { AIAgentInput } from '../ai-agent/ai-agent.types.js';
|
|
11
20
|
import type { StreamAIAgentOptions } from '../ai-agent/ai-agent-prepare.js';
|
|
12
21
|
/**
|
|
@@ -32,6 +41,15 @@ export declare class ContextAwareRPCService {
|
|
|
32
41
|
* @private
|
|
33
42
|
*/
|
|
34
43
|
private invokeAddonFunction;
|
|
44
|
+
/**
|
|
45
|
+
* Dispatch a `wireRemoteAddon` RPC over HTTP to the hosting service.
|
|
46
|
+
*
|
|
47
|
+
* The consumer sends the addon's own function name (not the namespaced form)
|
|
48
|
+
* to the host's `/remote/rpc/:rpcName` endpoint, authenticating as a client
|
|
49
|
+
* with the token bound in `wireRemoteAddon({ auth })`. The addon's handlers
|
|
50
|
+
* live on the host, so there is no local function meta to resolve.
|
|
51
|
+
*/
|
|
52
|
+
private invokeRemoteAddonFunction;
|
|
35
53
|
rpcWithWire<In = any, Out = any>(rpcName: string, data: In, wire: PikkuRawWire): Promise<Out>;
|
|
36
54
|
startWorkflow<In = any>(workflowName: string, input: In, options?: {
|
|
37
55
|
startNode?: string;
|
|
@@ -103,5 +121,6 @@ export declare const rpcService: PikkuRPCService<import("../../types/core.types.
|
|
|
103
121
|
logLevel?: import("../../services/logger.js").LogLevel;
|
|
104
122
|
secrets?: {};
|
|
105
123
|
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
|
|
124
|
+
webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
|
|
106
125
|
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
107
126
|
}>, PikkuRPC>;
|