@valon-technologies/gestalt 0.0.1-alpha.11 → 0.0.1-alpha.13

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/src/cache.ts CHANGED
@@ -1,13 +1,16 @@
1
1
  import { connect } from "node:net";
2
2
 
3
- import { createClient, type Client } from "@connectrpc/connect";
3
+ import { createClient, type Client, type Interceptor } from "@connectrpc/connect";
4
4
  import { createGrpcTransport } from "@connectrpc/connect-node";
5
5
 
6
6
  import { Cache as CacheService } from "../gen/v1/cache_pb.ts";
7
7
  import { RuntimeProvider, type RuntimeProviderOptions } from "./provider.ts";
8
8
  import type { MaybePromise } from "./api.ts";
9
9
 
10
- const ENV_CACHE_SOCKET = "GESTALT_CACHE_SOCKET";
10
+ export const ENV_CACHE_SOCKET = "GESTALT_CACHE_SOCKET";
11
+ const CACHE_SOCKET_TOKEN_SUFFIX = "_TOKEN";
12
+ const CACHE_RELAY_TOKEN_HEADER = "x-gestalt-host-service-relay-token";
13
+ export const ENV_CACHE_SOCKET_TOKEN = `${ENV_CACHE_SOCKET}${CACHE_SOCKET_TOKEN_SUFFIX}`;
11
14
 
12
15
  /**
13
16
  * Single cache entry used by batch cache APIs.
@@ -55,6 +58,49 @@ export function cacheSocketEnv(name?: string): string {
55
58
  return `${ENV_CACHE_SOCKET}_${trimmed.replace(/[^A-Za-z0-9]/gu, "_").toUpperCase()}`;
56
59
  }
57
60
 
61
+ /**
62
+ * Returns the environment variable name used to discover a cache relay token.
63
+ */
64
+ export function cacheSocketTokenEnv(name?: string): string {
65
+ return `${cacheSocketEnv(name)}${CACHE_SOCKET_TOKEN_SUFFIX}`;
66
+ }
67
+
68
+ function cacheTransportOptions(rawTarget: string): {
69
+ baseUrl: string;
70
+ nodeOptions?: { path: string };
71
+ } {
72
+ const target = rawTarget.trim();
73
+ if (!target) {
74
+ throw new Error("cache transport target is required");
75
+ }
76
+ if (target.startsWith("tcp://")) {
77
+ const address = target.slice("tcp://".length).trim();
78
+ if (!address) {
79
+ throw new Error(`cache tcp target ${JSON.stringify(rawTarget)} is missing host:port`);
80
+ }
81
+ return { baseUrl: `http://${address}` };
82
+ }
83
+ if (target.startsWith("tls://")) {
84
+ const address = target.slice("tls://".length).trim();
85
+ if (!address) {
86
+ throw new Error(`cache tls target ${JSON.stringify(rawTarget)} is missing host:port`);
87
+ }
88
+ return { baseUrl: `https://${address}` };
89
+ }
90
+ if (target.startsWith("unix://")) {
91
+ const socketPath = target.slice("unix://".length).trim();
92
+ if (!socketPath) {
93
+ throw new Error(`cache unix target ${JSON.stringify(rawTarget)} is missing a socket path`);
94
+ }
95
+ return { baseUrl: "http://localhost", nodeOptions: { path: socketPath } };
96
+ }
97
+ if (target.includes("://")) {
98
+ const parsed = new URL(target);
99
+ throw new Error(`Unsupported cache target scheme ${JSON.stringify(parsed.protocol.replace(/:$/, ""))}`);
100
+ }
101
+ return { baseUrl: "http://localhost", nodeOptions: { path: target } };
102
+ }
103
+
58
104
  /**
59
105
  * Client for invoking a host-provided cache over the Gestalt transport.
60
106
  *
@@ -71,16 +117,30 @@ export class Cache {
71
117
 
72
118
  constructor(name?: string) {
73
119
  const envName = cacheSocketEnv(name);
74
- const socketPath = process.env[envName];
75
- if (!socketPath) {
120
+ const target = process.env[envName];
121
+ if (!target) {
76
122
  throw new Error(`cache: ${envName} is not set`);
77
123
  }
78
-
124
+ const token = process.env[cacheSocketTokenEnv(name)]?.trim() ?? "";
125
+ const transportOptions = cacheTransportOptions(target);
126
+ const interceptors: Interceptor[] = token
127
+ ? [
128
+ (next) => async (req) => {
129
+ req.header.set(CACHE_RELAY_TOKEN_HEADER, token);
130
+ return await next(req);
131
+ },
132
+ ]
133
+ : [];
79
134
  const transport = createGrpcTransport({
80
- baseUrl: "http://localhost",
81
- nodeOptions: {
82
- createConnection: () => connect(socketPath),
83
- },
135
+ ...transportOptions,
136
+ ...(transportOptions.nodeOptions
137
+ ? {
138
+ nodeOptions: {
139
+ createConnection: () => connect(transportOptions.nodeOptions!.path),
140
+ },
141
+ }
142
+ : {}),
143
+ interceptors,
84
144
  });
85
145
  this.client = createClient(CacheService, transport);
86
146
  }
@@ -0,0 +1,113 @@
1
+ import type { Access, Credential, MaybePromise, Subject } from "./api.ts";
2
+
3
+ /**
4
+ * Verified hosted HTTP request metadata passed into optional plugin-local
5
+ * subject resolution hooks before normal operation dispatch.
6
+ */
7
+ export interface HTTPSubjectRequest {
8
+ binding: string;
9
+ method: string;
10
+ path: string;
11
+ contentType: string;
12
+ headers: Record<string, string[]>;
13
+ query: Record<string, string[]>;
14
+ params: Record<string, unknown>;
15
+ rawBody: Uint8Array;
16
+ securityScheme: string;
17
+ verifiedSubject: string;
18
+ verifiedClaims: Record<string, string>;
19
+ }
20
+
21
+ /**
22
+ * Request-scoped caller context available while resolving the concrete subject
23
+ * for a hosted HTTP request.
24
+ */
25
+ export interface HTTPSubjectResolutionContext {
26
+ subject: Subject;
27
+ credential: Credential;
28
+ access: Access;
29
+ workflow: Record<string, unknown>;
30
+ }
31
+
32
+ /**
33
+ * Explicit HTTP rejection surfaced from a hosted HTTP subject resolver.
34
+ */
35
+ export class HTTPSubjectResolutionError extends Error {
36
+ readonly status: number;
37
+
38
+ constructor(status: number, message: string) {
39
+ super(message);
40
+ this.name = "HTTPSubjectResolutionError";
41
+ this.status = status;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Creates an explicit hosted HTTP subject-resolution rejection.
47
+ */
48
+ export function httpSubjectError(
49
+ status: number,
50
+ message: string,
51
+ ): HTTPSubjectResolutionError {
52
+ return new HTTPSubjectResolutionError(status, message);
53
+ }
54
+
55
+ /**
56
+ * Optional hook that maps a verified hosted HTTP request to a concrete Gestalt
57
+ * subject before the target operation is authorized and executed.
58
+ */
59
+ export type HTTPSubjectResolver = (
60
+ request: HTTPSubjectRequest,
61
+ context: HTTPSubjectResolutionContext,
62
+ ) => MaybePromise<Subject | null | undefined>;
63
+
64
+ export function cloneHTTPSubjectRequest(
65
+ input: HTTPSubjectRequest,
66
+ ): HTTPSubjectRequest {
67
+ return {
68
+ binding: input.binding,
69
+ method: input.method,
70
+ path: input.path,
71
+ contentType: input.contentType,
72
+ headers: cloneStringLists(input.headers),
73
+ query: cloneStringLists(input.query),
74
+ params: {
75
+ ...input.params,
76
+ },
77
+ rawBody: new Uint8Array(input.rawBody),
78
+ securityScheme: input.securityScheme,
79
+ verifiedSubject: input.verifiedSubject,
80
+ verifiedClaims: {
81
+ ...input.verifiedClaims,
82
+ },
83
+ };
84
+ }
85
+
86
+ export function cloneHTTPSubjectResolutionContext(
87
+ input: HTTPSubjectResolutionContext,
88
+ ): HTTPSubjectResolutionContext {
89
+ return {
90
+ subject: {
91
+ ...input.subject,
92
+ },
93
+ credential: {
94
+ ...input.credential,
95
+ },
96
+ access: {
97
+ ...input.access,
98
+ },
99
+ workflow: {
100
+ ...input.workflow,
101
+ },
102
+ };
103
+ }
104
+
105
+ function cloneStringLists(
106
+ input: Record<string, string[]>,
107
+ ): Record<string, string[]> {
108
+ const output: Record<string, string[]> = {};
109
+ for (const [key, value] of Object.entries(input)) {
110
+ output[key] = [...value];
111
+ }
112
+ return output;
113
+ }
package/src/index.ts CHANGED
@@ -28,6 +28,23 @@
28
28
  * import { parseRuntimeArgs, serve } from "@valon-technologies/gestalt/runtime";
29
29
  * ```
30
30
  */
31
+ export {
32
+ Authorization,
33
+ AuthorizationClient,
34
+ ENV_AUTHORIZATION_SOCKET,
35
+ ENV_AUTHORIZATION_SOCKET_TOKEN,
36
+ type AuthorizationActionSearchMessage,
37
+ type AuthorizationDecisionMessage,
38
+ type AuthorizationEvaluateInput,
39
+ type AuthorizationMetadataMessage,
40
+ type AuthorizationReadRelationshipsInput,
41
+ type AuthorizationReadRelationshipsMessage,
42
+ type AuthorizationResourceSearchMessage,
43
+ type AuthorizationSearchActionsInput,
44
+ type AuthorizationSearchResourcesInput,
45
+ type AuthorizationSearchSubjectsInput,
46
+ type AuthorizationSubjectSearchMessage,
47
+ } from "./authorization.ts";
31
48
  export {
32
49
  connectionParam,
33
50
  ok,
@@ -42,6 +59,13 @@ export {
42
59
  type Response,
43
60
  type Subject,
44
61
  } from "./api.ts";
62
+ export {
63
+ type HTTPSubjectRequest,
64
+ type HTTPSubjectResolutionContext,
65
+ HTTPSubjectResolutionError,
66
+ type HTTPSubjectResolver,
67
+ httpSubjectError,
68
+ } from "./http-subject.ts";
45
69
  export {
46
70
  catalogToJson,
47
71
  catalogToYaml,
@@ -76,20 +100,47 @@ export {
76
100
  } from "./build.ts";
77
101
  export {
78
102
  ENV_PLUGIN_INVOKER_SOCKET,
103
+ ENV_PLUGIN_INVOKER_SOCKET_TOKEN,
79
104
  PluginInvoker,
80
105
  type PluginGraphQLInvokeOptions,
81
106
  type PluginInvocationGrant,
82
107
  type PluginInvokeOptions,
83
108
  } from "./invoker.ts";
109
+ export {
110
+ ENV_AGENT_MANAGER_SOCKET,
111
+ ENV_AGENT_MANAGER_SOCKET_TOKEN,
112
+ AgentManager,
113
+ type AgentManagerCancelTurnInput,
114
+ type AgentManagerCreateSessionInput,
115
+ type AgentManagerCreateTurnInput,
116
+ type AgentManagerGetSessionInput,
117
+ type AgentManagerGetTurnInput,
118
+ type AgentManagerListInteractionsInput,
119
+ type AgentManagerListSessionsInput,
120
+ type AgentManagerListTurnEventsInput,
121
+ type AgentManagerListTurnsInput,
122
+ type AgentManagerResolveInteractionInput,
123
+ type AgentManagerUpdateSessionInput,
124
+ } from "./agent-manager.ts";
84
125
  export {
85
126
  ENV_WORKFLOW_MANAGER_SOCKET,
127
+ ENV_WORKFLOW_MANAGER_SOCKET_TOKEN,
86
128
  WorkflowManager,
129
+ type ManagedWorkflowEventTriggerMessage,
87
130
  type ManagedWorkflowScheduleMessage,
131
+ type WorkflowEventMessage,
132
+ type WorkflowManagerCreateTriggerInput,
88
133
  type WorkflowManagerCreateScheduleInput,
134
+ type WorkflowManagerDeleteTriggerInput,
89
135
  type WorkflowManagerDeleteScheduleInput,
136
+ type WorkflowManagerGetTriggerInput,
90
137
  type WorkflowManagerGetScheduleInput,
138
+ type WorkflowManagerPauseTriggerInput,
91
139
  type WorkflowManagerPauseScheduleInput,
140
+ type WorkflowManagerPublishEventInput,
141
+ type WorkflowManagerResumeTriggerInput,
92
142
  type WorkflowManagerResumeScheduleInput,
143
+ type WorkflowManagerUpdateTriggerInput,
93
144
  type WorkflowManagerUpdateScheduleInput,
94
145
  } from "./workflow-manager.ts";
95
146
  export {
@@ -107,8 +158,11 @@ export {
107
158
  Cache,
108
159
  CacheProvider,
109
160
  cacheSocketEnv,
161
+ cacheSocketTokenEnv,
110
162
  defineCacheProvider,
111
163
  isCacheProvider,
164
+ ENV_CACHE_SOCKET,
165
+ ENV_CACHE_SOCKET_TOKEN,
112
166
  type CacheEntry,
113
167
  type CacheProviderOptions,
114
168
  type CacheSetOptions,
@@ -119,6 +173,7 @@ export {
119
173
  type SecretsProviderOptions,
120
174
  } from "./secrets.ts";
121
175
  export {
176
+ type ConnectedToken,
122
177
  PluginProvider,
123
178
  connectionModeToProtoValue,
124
179
  connectionParamToProto,
@@ -129,6 +184,7 @@ export {
129
184
  type ConnectionParamDefinition,
130
185
  type OperationDefinition,
131
186
  type OperationOptions,
187
+ type PostConnectHandler,
132
188
  type PluginDefinitionOptions,
133
189
  type SessionCatalog,
134
190
  type SessionCatalogHandler,
@@ -200,6 +256,7 @@ export {
200
256
  AlreadyExistsError,
201
257
  ColumnType,
202
258
  indexedDBSocketEnv,
259
+ indexedDBSocketTokenEnv,
203
260
  type Record,
204
261
  type KeyRange,
205
262
  type ColumnSchema,
@@ -218,7 +275,10 @@ export {
218
275
  createS3Service,
219
276
  defineS3Provider,
220
277
  isS3Provider,
278
+ ENV_S3_SOCKET,
279
+ ENV_S3_SOCKET_TOKEN,
221
280
  s3SocketEnv,
281
+ s3SocketTokenEnv,
222
282
  type ByteRange,
223
283
  type CopyOptions,
224
284
  type ListOptions,
@@ -234,6 +294,50 @@ export {
234
294
  type S3ProviderOptions,
235
295
  type WriteOptions,
236
296
  } from "./s3.ts";
297
+ export {
298
+ ENV_AGENT_HOST_SOCKET,
299
+ AgentHost,
300
+ AgentExecutionStatus,
301
+ AgentInteractionState,
302
+ AgentInteractionType,
303
+ AgentMessagePartType,
304
+ AgentProvider,
305
+ AgentSessionState,
306
+ AgentToolSourceMode,
307
+ createAgentProviderService,
308
+ defineAgentProvider,
309
+ isAgentProvider,
310
+ type AgentActor,
311
+ type AgentInteraction,
312
+ type AgentMessage,
313
+ type AgentMessagePart,
314
+ type AgentMessagePartImageRef,
315
+ type AgentMessagePartToolCall,
316
+ type AgentMessagePartToolResult,
317
+ type AgentProviderCapabilities,
318
+ type AgentProviderOptions,
319
+ type AgentSession,
320
+ type AgentToolRef,
321
+ type AgentTurn,
322
+ type AgentTurnEvent,
323
+ type BoundAgentToolTarget,
324
+ type CancelAgentProviderTurnRequest,
325
+ type CreateAgentProviderSessionRequest,
326
+ type CreateAgentProviderTurnRequest,
327
+ type ExecuteAgentToolRequest,
328
+ type ExecuteAgentToolResponse,
329
+ type GetAgentProviderCapabilitiesRequest,
330
+ type GetAgentProviderInteractionRequest,
331
+ type GetAgentProviderSessionRequest,
332
+ type GetAgentProviderTurnRequest,
333
+ type ListAgentProviderInteractionsRequest,
334
+ type ListAgentProviderSessionsRequest,
335
+ type ListAgentProviderTurnEventsRequest,
336
+ type ListAgentProviderTurnsRequest,
337
+ type ResolvedAgentTool,
338
+ type ResolveAgentProviderInteractionRequest,
339
+ type UpdateAgentProviderSessionRequest,
340
+ } from "./agent.ts";
237
341
  export {
238
342
  ENV_WORKFLOW_HOST_SOCKET,
239
343
  WorkflowHost,
package/src/indexeddb.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { createClient, type Client } from "@connectrpc/connect";
1
+ import { createClient, type Client, type Interceptor } from "@connectrpc/connect";
2
2
  import { createGrpcTransport } from "@connectrpc/connect-node";
3
3
  import {
4
4
  IndexedDB as IndexedDBService,
@@ -6,6 +6,8 @@ import {
6
6
  } from "../gen/v1/datastore_pb";
7
7
 
8
8
  const ENV_INDEXEDDB_SOCKET = "GESTALT_INDEXEDDB_SOCKET";
9
+ const INDEXEDDB_SOCKET_TOKEN_SUFFIX = "_TOKEN";
10
+ const INDEXEDDB_RELAY_TOKEN_HEADER = "x-gestalt-host-service-relay-token";
9
11
 
10
12
  /**
11
13
  * Returns the environment variable name used to discover an IndexedDB socket.
@@ -16,6 +18,49 @@ export function indexedDBSocketEnv(name?: string): string {
16
18
  return `${ENV_INDEXEDDB_SOCKET}_${trimmed.replace(/[^A-Za-z0-9]/g, "_").toUpperCase()}`;
17
19
  }
18
20
 
21
+ /**
22
+ * Returns the environment variable name used to discover an IndexedDB relay token.
23
+ */
24
+ export function indexedDBSocketTokenEnv(name?: string): string {
25
+ return `${indexedDBSocketEnv(name)}${INDEXEDDB_SOCKET_TOKEN_SUFFIX}`;
26
+ }
27
+
28
+ function indexedDBTransportOptions(rawTarget: string): {
29
+ baseUrl: string;
30
+ nodeOptions?: { path: string };
31
+ } {
32
+ const target = rawTarget.trim();
33
+ if (!target) {
34
+ throw new Error("IndexedDB transport target is required");
35
+ }
36
+ if (target.startsWith("tcp://")) {
37
+ const address = target.slice("tcp://".length).trim();
38
+ if (!address) {
39
+ throw new Error(`IndexedDB tcp target ${JSON.stringify(rawTarget)} is missing host:port`);
40
+ }
41
+ return { baseUrl: `http://${address}` };
42
+ }
43
+ if (target.startsWith("tls://")) {
44
+ const address = target.slice("tls://".length).trim();
45
+ if (!address) {
46
+ throw new Error(`IndexedDB tls target ${JSON.stringify(rawTarget)} is missing host:port`);
47
+ }
48
+ return { baseUrl: `https://${address}` };
49
+ }
50
+ if (target.startsWith("unix://")) {
51
+ const socketPath = target.slice("unix://".length).trim();
52
+ if (!socketPath) {
53
+ throw new Error(`IndexedDB unix target ${JSON.stringify(rawTarget)} is missing a socket path`);
54
+ }
55
+ return { baseUrl: "http://localhost", nodeOptions: { path: socketPath } };
56
+ }
57
+ if (target.includes("://")) {
58
+ const parsed = new URL(target);
59
+ throw new Error(`Unsupported IndexedDB target scheme ${JSON.stringify(parsed.protocol.replace(/:$/, ""))}`);
60
+ }
61
+ return { baseUrl: "http://localhost", nodeOptions: { path: target } };
62
+ }
63
+
19
64
  class AsyncQueue<T> implements AsyncIterable<T> {
20
65
  private queue: T[] = [];
21
66
  private waiting: ((result: IteratorResult<T>) => void) | null = null;
@@ -447,15 +492,16 @@ export interface ObjectStoreSchema {
447
492
  export class IndexedDB {
448
493
  private client: Client<typeof IndexedDBService>;
449
494
 
450
- constructor(name?: string) {
495
+ constructor(name?: string) {
451
496
  const envName = indexedDBSocketEnv(name);
452
- const socketPath = process.env[envName];
453
- if (!socketPath) {
497
+ const target = process.env[envName];
498
+ if (!target) {
454
499
  throw new Error(`${envName} is not set`);
455
500
  }
501
+ const token = process.env[indexedDBSocketTokenEnv(name)]?.trim() ?? "";
456
502
  const transport = createGrpcTransport({
457
- baseUrl: `http://localhost`,
458
- nodeOptions: { path: socketPath },
503
+ ...indexedDBTransportOptions(target),
504
+ interceptors: token ? [indexedDBRelayTokenInterceptor(token)] : [],
459
505
  });
460
506
  this.client = createClient(IndexedDBService, transport);
461
507
  }
@@ -498,6 +544,13 @@ export class IndexedDB {
498
544
  }
499
545
  }
500
546
 
547
+ function indexedDBRelayTokenInterceptor(token: string): Interceptor {
548
+ return (next) => async (req) => {
549
+ req.header.set(INDEXEDDB_RELAY_TOKEN_HEADER, token);
550
+ return next(req);
551
+ };
552
+ }
553
+
501
554
  /**
502
555
  * Object store client used for primary-key operations.
503
556
  */
package/src/invoker.ts CHANGED
@@ -1,13 +1,13 @@
1
- import { connect } from "node:net";
2
-
3
1
  import type { JsonObject, JsonValue } from "@bufbuild/protobuf";
4
- import { createClient, type Client } from "@connectrpc/connect";
2
+ import { createClient, type Client, type Interceptor } from "@connectrpc/connect";
5
3
  import { createGrpcTransport } from "@connectrpc/connect-node";
6
4
 
7
5
  import { PluginInvoker as PluginInvokerService } from "../gen/v1/plugin_pb.ts";
8
6
  import type { OperationResult, Request } from "./api.ts";
9
7
 
10
8
  export const ENV_PLUGIN_INVOKER_SOCKET = "GESTALT_PLUGIN_INVOKER_SOCKET";
9
+ export const ENV_PLUGIN_INVOKER_SOCKET_TOKEN = `${ENV_PLUGIN_INVOKER_SOCKET}_TOKEN`;
10
+ const PLUGIN_INVOKER_RELAY_TOKEN_HEADER = "x-gestalt-host-service-relay-token";
11
11
 
12
12
  export interface PluginInvokeOptions {
13
13
  connection?: string;
@@ -38,12 +38,11 @@ export class PluginInvoker {
38
38
  if (!socketPath) {
39
39
  throw new Error(`plugin invoker: ${ENV_PLUGIN_INVOKER_SOCKET} is not set`);
40
40
  }
41
+ const relayToken = process.env[ENV_PLUGIN_INVOKER_SOCKET_TOKEN]?.trim() ?? "";
41
42
 
42
43
  const transport = createGrpcTransport({
43
- baseUrl: "http://localhost",
44
- nodeOptions: {
45
- createConnection: () => connect(socketPath),
46
- },
44
+ ...pluginInvokerTransportOptions(socketPath),
45
+ interceptors: relayToken ? [pluginInvokerRelayTokenInterceptor(relayToken)] : [],
47
46
  });
48
47
  this.client = createClient(PluginInvokerService, transport);
49
48
  }
@@ -118,6 +117,49 @@ export class PluginInvoker {
118
117
  }
119
118
  }
120
119
 
120
+ function pluginInvokerTransportOptions(rawTarget: string): {
121
+ baseUrl: string;
122
+ nodeOptions?: { path: string };
123
+ } {
124
+ const target = rawTarget.trim();
125
+ if (!target) {
126
+ throw new Error("plugin invoker: transport target is required");
127
+ }
128
+ if (target.startsWith("tcp://")) {
129
+ const address = target.slice("tcp://".length).trim();
130
+ if (!address) {
131
+ throw new Error(`plugin invoker: tcp target ${JSON.stringify(rawTarget)} is missing host:port`);
132
+ }
133
+ return { baseUrl: `http://${address}` };
134
+ }
135
+ if (target.startsWith("tls://")) {
136
+ const address = target.slice("tls://".length).trim();
137
+ if (!address) {
138
+ throw new Error(`plugin invoker: tls target ${JSON.stringify(rawTarget)} is missing host:port`);
139
+ }
140
+ return { baseUrl: `https://${address}` };
141
+ }
142
+ if (target.startsWith("unix://")) {
143
+ const socketPath = target.slice("unix://".length).trim();
144
+ if (!socketPath) {
145
+ throw new Error(`plugin invoker: unix target ${JSON.stringify(rawTarget)} is missing a socket path`);
146
+ }
147
+ return { baseUrl: "http://localhost", nodeOptions: { path: socketPath } };
148
+ }
149
+ if (target.includes("://")) {
150
+ const parsed = new URL(target);
151
+ throw new Error(`plugin invoker: unsupported target scheme ${JSON.stringify(parsed.protocol.replace(/:$/, ""))}`);
152
+ }
153
+ return { baseUrl: "http://localhost", nodeOptions: { path: target } };
154
+ }
155
+
156
+ function pluginInvokerRelayTokenInterceptor(token: string): Interceptor {
157
+ return (next) => async (req) => {
158
+ req.header.set(PLUGIN_INVOKER_RELAY_TOKEN_HEADER, token);
159
+ return next(req);
160
+ };
161
+ }
162
+
121
163
  function normalizeInvocationToken(requestOrToken: Request | string): string {
122
164
  const invocationToken =
123
165
  typeof requestOrToken === "string"
@@ -3,7 +3,7 @@ import { writeFileSync } from "node:fs";
3
3
  import YAML from "yaml";
4
4
 
5
5
  export type HTTPSecuritySchemeType =
6
- | "slack_signature"
6
+ | "hmac"
7
7
  | "apiKey"
8
8
  | "http"
9
9
  | "none";
@@ -20,6 +20,11 @@ export interface HTTPSecretRef {
20
20
  export interface HTTPSecurityScheme {
21
21
  type?: HTTPSecuritySchemeType;
22
22
  description?: string;
23
+ signatureHeader?: string;
24
+ signaturePrefix?: string;
25
+ payloadTemplate?: string;
26
+ timestampHeader?: string;
27
+ maxAgeSeconds?: number;
23
28
  name?: string;
24
29
  in?: HTTPIn;
25
30
  scheme?: HTTPAuthScheme;
@@ -42,6 +47,7 @@ export interface HTTPAck {
42
47
  export interface HTTPBinding {
43
48
  path: string;
44
49
  method: string;
50
+ credentialMode?: "none" | "user";
45
51
  requestBody?: HTTPRequestBody;
46
52
  security: string;
47
53
  target: string;