@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.
Files changed (198) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/dist/dev/hot-reload.js +13 -55
  3. package/dist/dev/module-runner.d.ts +14 -0
  4. package/dist/dev/module-runner.js +59 -0
  5. package/dist/dev/reload-meta.d.ts +13 -0
  6. package/dist/dev/reload-meta.js +22 -0
  7. package/dist/errors/errors.d.ts +12 -0
  8. package/dist/errors/errors.js +19 -0
  9. package/dist/function/function-runner.d.ts +5 -5
  10. package/dist/function/function-runner.js +39 -111
  11. package/dist/function/functions.types.d.ts +17 -7
  12. package/dist/index.d.ts +5 -1
  13. package/dist/index.js +3 -1
  14. package/dist/middleware/auth-apikey.d.ts +1 -0
  15. package/dist/middleware/auth-bearer.d.ts +1 -0
  16. package/dist/middleware/auth-cookie.d.ts +1 -0
  17. package/dist/middleware/cors.d.ts +1 -0
  18. package/dist/middleware/index.d.ts +1 -1
  19. package/dist/middleware/index.js +1 -1
  20. package/dist/middleware/remote-auth.d.ts +1 -0
  21. package/dist/middleware/telemetry.d.ts +2 -0
  22. package/dist/middleware/timeout.d.ts +1 -0
  23. package/dist/permissions.d.ts +32 -25
  24. package/dist/permissions.js +104 -185
  25. package/dist/pikku-state.js +0 -2
  26. package/dist/scopes.d.ts +17 -0
  27. package/dist/scopes.js +59 -0
  28. package/dist/services/ai-embedding-service.d.ts +31 -0
  29. package/dist/services/ai-embedding-service.js +1 -0
  30. package/dist/services/credential-wire-service.d.ts +3 -1
  31. package/dist/services/credential-wire-service.js +10 -4
  32. package/dist/services/index.d.ts +4 -0
  33. package/dist/services/index.js +2 -0
  34. package/dist/services/meta-service.d.ts +15 -2
  35. package/dist/services/meta-service.js +51 -1
  36. package/dist/services/queue-webhook-service.d.ts +55 -0
  37. package/dist/services/queue-webhook-service.js +136 -0
  38. package/dist/services/scope-service.d.ts +67 -0
  39. package/dist/services/scope-service.js +1 -0
  40. package/dist/services/typed-secret-service.d.ts +8 -0
  41. package/dist/services/typed-secret-service.js +39 -4
  42. package/dist/services/webhook-service.d.ts +140 -0
  43. package/dist/services/webhook-service.js +44 -0
  44. package/dist/services/workflow-service.d.ts +7 -0
  45. package/dist/types/core.types.d.ts +34 -6
  46. package/dist/types/state.types.d.ts +20 -2
  47. package/dist/utils/hmac.d.ts +16 -0
  48. package/dist/utils/hmac.js +26 -0
  49. package/dist/utils/safe-fetch.d.ts +51 -0
  50. package/dist/utils/safe-fetch.js +192 -0
  51. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +84 -0
  52. package/dist/wirings/ai-agent/ai-agent-agui.js +305 -0
  53. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +41 -1
  54. package/dist/wirings/ai-agent/ai-agent-prepare.js +146 -6
  55. package/dist/wirings/ai-agent/ai-agent-runner.js +6 -1
  56. package/dist/wirings/ai-agent/ai-agent-stream.js +61 -10
  57. package/dist/wirings/ai-agent/ai-agent.types.d.ts +27 -1
  58. package/dist/wirings/ai-agent/index.d.ts +1 -0
  59. package/dist/wirings/ai-agent/index.js +1 -0
  60. package/dist/wirings/ai-agent/voice-input.d.ts +1 -0
  61. package/dist/wirings/ai-agent/voice-input.js +2 -38
  62. package/dist/wirings/ai-agent/voice-output.d.ts +1 -0
  63. package/dist/wirings/channel/channel-common.js +0 -1
  64. package/dist/wirings/channel/channel-handler.js +1 -4
  65. package/dist/wirings/channel/channel-middleware-runner.d.ts +12 -0
  66. package/dist/wirings/channel/channel-middleware-runner.js +34 -19
  67. package/dist/wirings/channel/channel.types.d.ts +2 -6
  68. package/dist/wirings/cli/cli-runner.js +0 -2
  69. package/dist/wirings/cli/cli.types.d.ts +1 -2
  70. package/dist/wirings/http/http-routes.js +0 -3
  71. package/dist/wirings/http/http-runner.d.ts +9 -29
  72. package/dist/wirings/http/http-runner.js +9 -34
  73. package/dist/wirings/http/http.types.d.ts +1 -9
  74. package/dist/wirings/mcp/mcp-runner.js +0 -2
  75. package/dist/wirings/mcp/mcp.types.d.ts +5 -11
  76. package/dist/wirings/oauth2/index.d.ts +0 -3
  77. package/dist/wirings/oauth2/index.js +1 -2
  78. package/dist/wirings/rpc/addon-runner.d.ts +28 -0
  79. package/dist/wirings/rpc/addon-runner.js +173 -0
  80. package/dist/wirings/rpc/index.d.ts +5 -1
  81. package/dist/wirings/rpc/index.js +3 -1
  82. package/dist/wirings/rpc/remote-addon-auth.d.ts +26 -0
  83. package/dist/wirings/rpc/remote-addon-auth.js +43 -0
  84. package/dist/wirings/rpc/rpc-runner.d.ts +19 -0
  85. package/dist/wirings/rpc/rpc-runner.js +109 -3
  86. package/dist/wirings/rpc/rpc-types.d.ts +15 -1
  87. package/dist/wirings/rpc/wire-addon.js +9 -0
  88. package/dist/wirings/rpc/wire-remote-addon.d.ts +47 -0
  89. package/dist/wirings/rpc/wire-remote-addon.js +19 -0
  90. package/dist/wirings/scope/index.d.ts +3 -0
  91. package/dist/wirings/scope/index.js +2 -0
  92. package/dist/wirings/scope/scope.types.d.ts +39 -0
  93. package/dist/wirings/scope/scope.types.js +1 -0
  94. package/dist/wirings/scope/validate-scope-definitions.d.ts +16 -0
  95. package/dist/wirings/scope/validate-scope-definitions.js +76 -0
  96. package/dist/wirings/scope/wire-scope.d.ts +33 -0
  97. package/dist/wirings/scope/wire-scope.js +32 -0
  98. package/dist/wirings/workflow/dsl/index.d.ts +1 -1
  99. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +53 -1
  100. package/dist/wirings/workflow/graph/graph-node.d.ts +2 -0
  101. package/dist/wirings/workflow/graph/graph-runner.js +3 -0
  102. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +6 -0
  103. package/dist/wirings/workflow/graph/wire-workflow-graph.js +1 -0
  104. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +5 -0
  105. package/dist/wirings/workflow/index.d.ts +2 -2
  106. package/dist/wirings/workflow/index.js +1 -1
  107. package/dist/wirings/workflow/pikku-workflow-service.d.ts +51 -1
  108. package/dist/wirings/workflow/pikku-workflow-service.js +171 -0
  109. package/dist/wirings/workflow/workflow.types.d.ts +1 -1
  110. package/package.json +5 -1
  111. package/run-tests.sh +1 -0
  112. package/src/dev/hot-reload.ts +13 -68
  113. package/src/dev/module-runner.test.ts +169 -0
  114. package/src/dev/module-runner.ts +103 -0
  115. package/src/dev/reload-meta.test.ts +31 -2
  116. package/src/dev/reload-meta.ts +26 -0
  117. package/src/errors/errors.ts +24 -0
  118. package/src/function/function-runner.test.ts +276 -142
  119. package/src/function/function-runner.ts +52 -145
  120. package/src/function/functions.types.ts +28 -38
  121. package/src/index.ts +8 -6
  122. package/src/middleware/index.ts +1 -5
  123. package/src/permissions.test.ts +153 -372
  124. package/src/permissions.ts +139 -259
  125. package/src/pikku-state.ts +0 -2
  126. package/src/scopes.test.ts +167 -0
  127. package/src/scopes.ts +69 -0
  128. package/src/services/ai-embedding-service.ts +31 -0
  129. package/src/services/credential-wire-service.ts +10 -4
  130. package/src/services/index.ts +20 -0
  131. package/src/services/meta-service.ts +68 -3
  132. package/src/services/queue-webhook-service.test.ts +408 -0
  133. package/src/services/queue-webhook-service.ts +182 -0
  134. package/src/services/scope-service.ts +75 -0
  135. package/src/services/typed-secret-service.test.ts +35 -0
  136. package/src/services/typed-secret-service.ts +39 -4
  137. package/src/services/webhook-service.ts +180 -0
  138. package/src/services/workflow-service.ts +7 -0
  139. package/src/types/core.types.ts +42 -14
  140. package/src/types/state.types.ts +23 -3
  141. package/src/utils/hmac.ts +27 -0
  142. package/src/utils/safe-fetch.test.ts +373 -0
  143. package/src/utils/safe-fetch.ts +213 -0
  144. package/src/wirings/ai-agent/ai-agent-agui.test.ts +1127 -0
  145. package/src/wirings/ai-agent/ai-agent-agui.ts +386 -0
  146. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +308 -0
  147. package/src/wirings/ai-agent/ai-agent-prepare.ts +192 -8
  148. package/src/wirings/ai-agent/ai-agent-runner.test.ts +48 -1
  149. package/src/wirings/ai-agent/ai-agent-runner.ts +21 -0
  150. package/src/wirings/ai-agent/ai-agent-stream.test.ts +198 -10
  151. package/src/wirings/ai-agent/ai-agent-stream.ts +84 -10
  152. package/src/wirings/ai-agent/ai-agent.types.ts +28 -0
  153. package/src/wirings/ai-agent/index.ts +1 -0
  154. package/src/wirings/ai-agent/voice-input.ts +6 -35
  155. package/src/wirings/channel/channel-common.ts +0 -1
  156. package/src/wirings/channel/channel-handler.ts +1 -9
  157. package/src/wirings/channel/channel-middleware-runner.test.ts +28 -2
  158. package/src/wirings/channel/channel-middleware-runner.ts +39 -27
  159. package/src/wirings/channel/channel.types.ts +0 -6
  160. package/src/wirings/cli/cli-runner.ts +0 -2
  161. package/src/wirings/cli/cli.types.ts +0 -2
  162. package/src/wirings/http/http-routes.ts +0 -3
  163. package/src/wirings/http/http-runner.test.ts +1 -11
  164. package/src/wirings/http/http-runner.ts +16 -39
  165. package/src/wirings/http/http.types.ts +1 -10
  166. package/src/wirings/mcp/mcp-runner.ts +0 -2
  167. package/src/wirings/mcp/mcp.types.ts +3 -11
  168. package/src/wirings/oauth2/index.ts +0 -3
  169. package/src/wirings/rpc/addon-runner.ts +233 -0
  170. package/src/wirings/rpc/index.ts +17 -1
  171. package/src/wirings/rpc/remote-addon-auth.ts +69 -0
  172. package/src/wirings/rpc/rpc-runner.test.ts +319 -16
  173. package/src/wirings/rpc/rpc-runner.ts +155 -3
  174. package/src/wirings/rpc/rpc-types.ts +16 -5
  175. package/src/wirings/rpc/wire-addon.test.ts +6 -3
  176. package/src/wirings/rpc/wire-addon.ts +9 -0
  177. package/src/wirings/rpc/wire-remote-addon.ts +57 -0
  178. package/src/wirings/scope/index.ts +14 -0
  179. package/src/wirings/scope/scope.test.ts +135 -0
  180. package/src/wirings/scope/scope.types.ts +44 -0
  181. package/src/wirings/scope/validate-scope-definitions.ts +110 -0
  182. package/src/wirings/scope/wire-scope.ts +34 -0
  183. package/src/wirings/workflow/dsl/index.ts +4 -0
  184. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +61 -0
  185. package/src/wirings/workflow/graph/graph-node.ts +2 -0
  186. package/src/wirings/workflow/graph/graph-runner.test.ts +58 -0
  187. package/src/wirings/workflow/graph/graph-runner.ts +3 -0
  188. package/src/wirings/workflow/graph/wire-workflow-graph.ts +7 -0
  189. package/src/wirings/workflow/graph/workflow-graph.types.ts +5 -0
  190. package/src/wirings/workflow/index.ts +5 -0
  191. package/src/wirings/workflow/pikku-workflow-service.test.ts +341 -0
  192. package/src/wirings/workflow/pikku-workflow-service.ts +236 -0
  193. package/src/wirings/workflow/workflow-step-session.test.ts +21 -5
  194. package/src/wirings/workflow/workflow.types.ts +4 -0
  195. package/tsconfig.tsbuildinfo +1 -1
  196. package/src/wirings/oauth2/oauth2-client.test.ts +0 -930
  197. package/src/wirings/oauth2/oauth2-client.ts +0 -331
  198. 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, CorePermissionGroup, CorePikkuFunctionConfig } from '../../function/functions.types.js';
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 { CorePermissionGroup, CorePikkuFunctionConfig, CorePikkuFunctionSessionless, CorePikkuPermission } from '../../function/functions.types.js';
2
- import type { CorePikkuMiddleware, MiddlewareMetadata, PermissionMetadata } from '../../types/core.types.js';
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' | 'permissions'> & {
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' | 'permissions'> & {
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' | 'permissions'> & {
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,4 +1 @@
1
- export { OAuth2Client } from './oauth2-client.js';
2
- export { createOAuth2Handler } from './oauth2-routes.js';
3
- export type { CreateOAuth2HandlerOptions } from './oauth2-routes.js';
4
1
  export type { OAuth2AppCredential, OAuth2Token } from './oauth2.types.js';
@@ -1,2 +1 @@
1
- export { OAuth2Client } from './oauth2-client.js';
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>;