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

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/plugin.ts CHANGED
@@ -7,15 +7,6 @@ import {
7
7
  schemaToParameters,
8
8
  writeCatalogYaml,
9
9
  } from "./catalog.ts";
10
- import {
11
- type HTTPAck,
12
- type HTTPBinding,
13
- type HTTPRequestBody,
14
- type HTTPSecurityScheme,
15
- type PluginManifestMetadata,
16
- hasPluginManifestMetadata,
17
- writeManifestMetadataYaml,
18
- } from "./manifest-metadata.ts";
19
10
  import {
20
11
  errorMessage,
21
12
  type MaybePromise,
@@ -46,7 +37,7 @@ export type ConnectionMode =
46
37
  | "unspecified"
47
38
  | "none"
48
39
  | "user"
49
- | "identity";
40
+ | "platform";
50
41
 
51
42
  /**
52
43
  * Metadata for a single connection parameter exposed by a provider.
@@ -131,8 +122,6 @@ export interface PluginDefinitionOptions extends RuntimeProviderOptions {
131
122
  connectionMode?: ConnectionMode;
132
123
  authTypes?: string[];
133
124
  connectionParams?: Record<string, ConnectionParamDefinition>;
134
- securitySchemes?: Record<string, HTTPSecurityScheme>;
135
- http?: Record<string, HTTPBinding>;
136
125
  resolveHTTPSubject?: HTTPSubjectResolver;
137
126
  postConnect?: PostConnectHandler;
138
127
  iconSvg?: string;
@@ -187,8 +176,6 @@ export class PluginProvider extends RuntimeProvider {
187
176
  readonly connectionMode: ConnectionMode;
188
177
  readonly authTypes: string[];
189
178
  readonly connectionParams: Record<string, ConnectionParamDefinition>;
190
- readonly securitySchemes: Record<string, HTTPSecurityScheme>;
191
- readonly http: Record<string, HTTPBinding>;
192
179
 
193
180
  private readonly sessionCatalogHandler: SessionCatalogHandler | undefined;
194
181
  private readonly httpSubjectResolver: HTTPSubjectResolver | undefined;
@@ -201,8 +188,6 @@ export class PluginProvider extends RuntimeProvider {
201
188
  this.connectionMode = options.connectionMode ?? "unspecified";
202
189
  this.authTypes = [...(options.authTypes ?? [])];
203
190
  this.connectionParams = normalizeConnectionParams(options.connectionParams);
204
- this.securitySchemes = normalizeHTTPSecuritySchemes(options.securitySchemes);
205
- this.http = normalizeHTTPBindings(options.http);
206
191
  this.httpSubjectResolver = options.resolveHTTPSubject;
207
192
  this.postConnectHandler = options.postConnect;
208
193
  this.sessionCatalogHandler = options.sessionCatalog;
@@ -346,38 +331,6 @@ export class PluginProvider extends RuntimeProvider {
346
331
  return catalogToJson(this.staticCatalog());
347
332
  }
348
333
 
349
- /**
350
- * Returns generated manifest-backed HTTP/security metadata for the provider.
351
- */
352
- staticManifestMetadata(): PluginManifestMetadata {
353
- const metadata: PluginManifestMetadata = {};
354
- if (Object.keys(this.securitySchemes).length > 0) {
355
- metadata.securitySchemes = cloneHTTPSecuritySchemes(this.securitySchemes);
356
- }
357
- if (Object.keys(this.http).length > 0) {
358
- metadata.http = cloneHTTPBindings(this.http);
359
- }
360
- return metadata;
361
- }
362
-
363
- /**
364
- * Reports whether the provider emits manifest metadata in addition to catalog metadata.
365
- */
366
- supportsManifestMetadata(): boolean {
367
- return hasPluginManifestMetadata(this.staticManifestMetadata());
368
- }
369
-
370
- /**
371
- * Writes generated manifest metadata to disk as YAML.
372
- */
373
- writeManifestMetadata(path: string): void {
374
- const metadata = this.staticManifestMetadata();
375
- if (!hasPluginManifestMetadata(metadata)) {
376
- return;
377
- }
378
- writeManifestMetadataYaml(path, metadata);
379
- }
380
-
381
334
  /**
382
335
  * Executes an operation against validated input and request metadata.
383
336
  */
@@ -448,10 +401,6 @@ export function isPluginProvider(
448
401
  typeof (value as { supportsSessionCatalog?: unknown }).supportsSessionCatalog === "function" &&
449
402
  "catalogForRequest" in value &&
450
403
  typeof (value as { catalogForRequest?: unknown }).catalogForRequest === "function" &&
451
- "supportsManifestMetadata" in value &&
452
- typeof (value as { supportsManifestMetadata?: unknown }).supportsManifestMetadata === "function" &&
453
- "writeManifestMetadata" in value &&
454
- typeof (value as { writeManifestMetadata?: unknown }).writeManifestMetadata === "function" &&
455
404
  "supportsPostConnect" in value &&
456
405
  typeof (value as { supportsPostConnect?: unknown }).supportsPostConnect === "function" &&
457
406
  "postConnectMetadata" in value &&
@@ -502,136 +451,6 @@ function cloneConnectedToken(token: ConnectedToken): ConnectedToken {
502
451
  };
503
452
  }
504
453
 
505
- function normalizeHTTPSecuritySchemes(
506
- input: Record<string, HTTPSecurityScheme> | undefined,
507
- ): Record<string, HTTPSecurityScheme> {
508
- const output: Record<string, HTTPSecurityScheme> = {};
509
- for (const [key, value] of Object.entries(input ?? {})) {
510
- output[key] = cloneHTTPSecurityScheme(value);
511
- }
512
- return output;
513
- }
514
-
515
- function cloneHTTPSecuritySchemes(
516
- input: Record<string, HTTPSecurityScheme>,
517
- ): Record<string, HTTPSecurityScheme> {
518
- const output: Record<string, HTTPSecurityScheme> = {};
519
- for (const [key, value] of Object.entries(input)) {
520
- output[key] = cloneHTTPSecurityScheme(value);
521
- }
522
- return output;
523
- }
524
-
525
- function cloneHTTPSecurityScheme(value: HTTPSecurityScheme): HTTPSecurityScheme {
526
- const output: HTTPSecurityScheme = {};
527
- if (value.type !== undefined) {
528
- output.type = value.type;
529
- }
530
- if (value.description !== undefined) {
531
- output.description = value.description;
532
- }
533
- if (value.signatureHeader !== undefined) {
534
- output.signatureHeader = value.signatureHeader;
535
- }
536
- if (value.signaturePrefix !== undefined) {
537
- output.signaturePrefix = value.signaturePrefix;
538
- }
539
- if (value.payloadTemplate !== undefined) {
540
- output.payloadTemplate = value.payloadTemplate;
541
- }
542
- if (value.timestampHeader !== undefined) {
543
- output.timestampHeader = value.timestampHeader;
544
- }
545
- if (value.maxAgeSeconds !== undefined) {
546
- output.maxAgeSeconds = value.maxAgeSeconds;
547
- }
548
- if (value.name !== undefined) {
549
- output.name = value.name;
550
- }
551
- if (value.in !== undefined) {
552
- output.in = value.in;
553
- }
554
- if (value.scheme !== undefined) {
555
- output.scheme = value.scheme;
556
- }
557
- if (value.secret) {
558
- output.secret = {
559
- ...value.secret,
560
- };
561
- }
562
- return output;
563
- }
564
-
565
- function normalizeHTTPBindings(
566
- input: Record<string, HTTPBinding> | undefined,
567
- ): Record<string, HTTPBinding> {
568
- const output: Record<string, HTTPBinding> = {};
569
- for (const [key, value] of Object.entries(input ?? {})) {
570
- output[key] = cloneHTTPBinding(value);
571
- }
572
- return output;
573
- }
574
-
575
- function cloneHTTPBindings(
576
- input: Record<string, HTTPBinding>,
577
- ): Record<string, HTTPBinding> {
578
- const output: Record<string, HTTPBinding> = {};
579
- for (const [key, value] of Object.entries(input)) {
580
- output[key] = cloneHTTPBinding(value);
581
- }
582
- return output;
583
- }
584
-
585
- function cloneHTTPBinding(value: HTTPBinding): HTTPBinding {
586
- const output: HTTPBinding = {
587
- path: value.path,
588
- method: value.method,
589
- security: value.security,
590
- target: value.target,
591
- };
592
- if (value.requestBody) {
593
- output.requestBody = cloneHTTPRequestBody(value.requestBody);
594
- }
595
- if (value.ack) {
596
- output.ack = cloneHTTPAck(value.ack);
597
- }
598
- return output;
599
- }
600
-
601
- function cloneHTTPRequestBody(value: HTTPRequestBody): HTTPRequestBody {
602
- const output: HTTPRequestBody = {};
603
- if (value.required !== undefined) {
604
- output.required = value.required;
605
- }
606
- if (value.content) {
607
- output.content = {};
608
- for (const key of Object.keys(value.content)) {
609
- output.content[key] = {};
610
- }
611
- }
612
- return output;
613
- }
614
-
615
- function cloneHTTPAck(value: HTTPAck): HTTPAck {
616
- const output: HTTPAck = {};
617
- if (value.status !== undefined) {
618
- output.status = value.status;
619
- }
620
- if (value.headers) {
621
- output.headers = {
622
- ...value.headers,
623
- };
624
- }
625
- if (value.body !== undefined) {
626
- output.body = cloneHTTPBodyValue(value.body);
627
- }
628
- return output;
629
- }
630
-
631
- function cloneHTTPBodyValue<T>(value: T): T {
632
- return structuredClone(value);
633
- }
634
-
635
454
  function isResponse(value: unknown): value is Response<unknown> {
636
455
  if (typeof value !== "object" || value === null) {
637
456
  return false;
@@ -696,8 +515,8 @@ export function connectionModeToProtoValue(mode: ConnectionMode): number {
696
515
  return 1;
697
516
  case "user":
698
517
  return 2;
699
- case "identity":
700
- return 3;
518
+ case "platform":
519
+ return 5;
701
520
  case "unspecified":
702
521
  default:
703
522
  return 0;
@@ -0,0 +1,220 @@
1
+ import { create, type MessageInitShape } from "@bufbuild/protobuf";
2
+ import { EmptySchema } from "@bufbuild/protobuf/wkt";
3
+ import {
4
+ Code,
5
+ ConnectError,
6
+ type ServiceImpl,
7
+ } from "@connectrpc/connect";
8
+
9
+ import {
10
+ HostedPluginSchema,
11
+ ListPluginRuntimeSessionsResponseSchema,
12
+ PluginRuntimeEgressMode,
13
+ PluginRuntimeHostServiceAccess,
14
+ PluginRuntimeHostServiceBindingSchema,
15
+ PluginRuntimeProvider as PluginRuntimeProviderService,
16
+ PluginRuntimeSessionSchema,
17
+ PluginRuntimeSupportSchema,
18
+ type BindPluginRuntimeHostServiceRequest,
19
+ type GetPluginRuntimeSessionRequest,
20
+ type HostedPlugin,
21
+ type ListPluginRuntimeSessionsRequest,
22
+ type PluginRuntimeHostServiceBinding,
23
+ type PluginRuntimeSession,
24
+ type PluginRuntimeSupport,
25
+ type StartHostedPluginRequest,
26
+ type StartPluginRuntimeSessionRequest,
27
+ type StopPluginRuntimeSessionRequest,
28
+ } from "../gen/v1/pluginruntime_pb.ts";
29
+ import { errorMessage, type MaybePromise } from "./api.ts";
30
+ import { RuntimeProvider, type RuntimeProviderOptions } from "./provider.ts";
31
+
32
+ export type {
33
+ BindPluginRuntimeHostServiceRequest,
34
+ GetPluginRuntimeSessionRequest,
35
+ HostedPlugin,
36
+ ListPluginRuntimeSessionsRequest,
37
+ PluginRuntimeHostServiceBinding,
38
+ PluginRuntimeSession,
39
+ PluginRuntimeSupport,
40
+ StartHostedPluginRequest,
41
+ StartPluginRuntimeSessionRequest,
42
+ StopPluginRuntimeSessionRequest,
43
+ };
44
+ export { PluginRuntimeEgressMode, PluginRuntimeHostServiceAccess };
45
+
46
+ export interface PluginRuntimeProviderOptions extends RuntimeProviderOptions {
47
+ getSupport: () => MaybePromise<MessageInitShape<typeof PluginRuntimeSupportSchema>>;
48
+ startSession: (
49
+ request: StartPluginRuntimeSessionRequest,
50
+ ) => MaybePromise<MessageInitShape<typeof PluginRuntimeSessionSchema>>;
51
+ getSession: (
52
+ request: GetPluginRuntimeSessionRequest,
53
+ ) => MaybePromise<MessageInitShape<typeof PluginRuntimeSessionSchema>>;
54
+ listSessions: (
55
+ request: ListPluginRuntimeSessionsRequest,
56
+ ) => MaybePromise<MessageInitShape<typeof PluginRuntimeSessionSchema>[]>;
57
+ stopSession: (request: StopPluginRuntimeSessionRequest) => MaybePromise<void>;
58
+ bindHostService: (
59
+ request: BindPluginRuntimeHostServiceRequest,
60
+ ) => MaybePromise<MessageInitShape<typeof PluginRuntimeHostServiceBindingSchema>>;
61
+ startPlugin: (
62
+ request: StartHostedPluginRequest,
63
+ ) => MaybePromise<MessageInitShape<typeof HostedPluginSchema>>;
64
+ }
65
+
66
+ export class PluginRuntimeProvider extends RuntimeProvider {
67
+ readonly kind = "runtime" as const;
68
+
69
+ private readonly getSupportHandler: PluginRuntimeProviderOptions["getSupport"];
70
+ private readonly startSessionHandler: PluginRuntimeProviderOptions["startSession"];
71
+ private readonly getSessionHandler: PluginRuntimeProviderOptions["getSession"];
72
+ private readonly listSessionsHandler: PluginRuntimeProviderOptions["listSessions"];
73
+ private readonly stopSessionHandler: PluginRuntimeProviderOptions["stopSession"];
74
+ private readonly bindHostServiceHandler: PluginRuntimeProviderOptions["bindHostService"];
75
+ private readonly startPluginHandler: PluginRuntimeProviderOptions["startPlugin"];
76
+
77
+ constructor(options: PluginRuntimeProviderOptions) {
78
+ super(options);
79
+ this.getSupportHandler = options.getSupport;
80
+ this.startSessionHandler = options.startSession;
81
+ this.getSessionHandler = options.getSession;
82
+ this.listSessionsHandler = options.listSessions;
83
+ this.stopSessionHandler = options.stopSession;
84
+ this.bindHostServiceHandler = options.bindHostService;
85
+ this.startPluginHandler = options.startPlugin;
86
+ }
87
+
88
+ async getSupport(): Promise<MessageInitShape<typeof PluginRuntimeSupportSchema>> {
89
+ return await this.getSupportHandler();
90
+ }
91
+
92
+ async startSession(
93
+ request: StartPluginRuntimeSessionRequest,
94
+ ): Promise<MessageInitShape<typeof PluginRuntimeSessionSchema>> {
95
+ return await this.startSessionHandler(request);
96
+ }
97
+
98
+ async getSession(
99
+ request: GetPluginRuntimeSessionRequest,
100
+ ): Promise<MessageInitShape<typeof PluginRuntimeSessionSchema>> {
101
+ return await this.getSessionHandler(request);
102
+ }
103
+
104
+ async listSessions(
105
+ request: ListPluginRuntimeSessionsRequest,
106
+ ): Promise<MessageInitShape<typeof PluginRuntimeSessionSchema>[]> {
107
+ return await this.listSessionsHandler(request);
108
+ }
109
+
110
+ async stopSession(request: StopPluginRuntimeSessionRequest): Promise<void> {
111
+ await this.stopSessionHandler(request);
112
+ }
113
+
114
+ async bindHostService(
115
+ request: BindPluginRuntimeHostServiceRequest,
116
+ ): Promise<MessageInitShape<typeof PluginRuntimeHostServiceBindingSchema>> {
117
+ return await this.bindHostServiceHandler(request);
118
+ }
119
+
120
+ async startPlugin(
121
+ request: StartHostedPluginRequest,
122
+ ): Promise<MessageInitShape<typeof HostedPluginSchema>> {
123
+ return await this.startPluginHandler(request);
124
+ }
125
+ }
126
+
127
+ export function definePluginRuntimeProvider(
128
+ options: PluginRuntimeProviderOptions,
129
+ ): PluginRuntimeProvider {
130
+ return new PluginRuntimeProvider(options);
131
+ }
132
+
133
+ export function isPluginRuntimeProvider(
134
+ value: unknown,
135
+ ): value is PluginRuntimeProvider {
136
+ return (
137
+ value instanceof PluginRuntimeProvider ||
138
+ (typeof value === "object" &&
139
+ value !== null &&
140
+ "kind" in value &&
141
+ (value as { kind?: unknown }).kind === "runtime" &&
142
+ "getSupport" in value &&
143
+ "startSession" in value &&
144
+ "startPlugin" in value)
145
+ );
146
+ }
147
+
148
+ export function createPluginRuntimeProviderService(
149
+ provider: PluginRuntimeProvider,
150
+ ): Partial<ServiceImpl<typeof PluginRuntimeProviderService>> {
151
+ return {
152
+ async getSupport() {
153
+ return create(
154
+ PluginRuntimeSupportSchema,
155
+ await invokePluginRuntimeProvider("get support", () =>
156
+ provider.getSupport(),
157
+ ),
158
+ );
159
+ },
160
+ async startSession(request) {
161
+ return create(
162
+ PluginRuntimeSessionSchema,
163
+ await invokePluginRuntimeProvider("start session", () =>
164
+ provider.startSession(request),
165
+ ),
166
+ );
167
+ },
168
+ async getSession(request) {
169
+ return create(
170
+ PluginRuntimeSessionSchema,
171
+ await invokePluginRuntimeProvider("get session", () =>
172
+ provider.getSession(request),
173
+ ),
174
+ );
175
+ },
176
+ async listSessions(request) {
177
+ return create(ListPluginRuntimeSessionsResponseSchema, {
178
+ sessions: await invokePluginRuntimeProvider("list sessions", () =>
179
+ provider.listSessions(request),
180
+ ),
181
+ });
182
+ },
183
+ async stopSession(request) {
184
+ await invokePluginRuntimeProvider("stop session", () =>
185
+ provider.stopSession(request),
186
+ );
187
+ return create(EmptySchema);
188
+ },
189
+ async bindHostService(request) {
190
+ return create(
191
+ PluginRuntimeHostServiceBindingSchema,
192
+ await invokePluginRuntimeProvider("bind host service", () =>
193
+ provider.bindHostService(request),
194
+ ),
195
+ );
196
+ },
197
+ async startPlugin(request) {
198
+ return create(
199
+ HostedPluginSchema,
200
+ await invokePluginRuntimeProvider("start plugin", () =>
201
+ provider.startPlugin(request),
202
+ ),
203
+ );
204
+ },
205
+ };
206
+ }
207
+
208
+ async function invokePluginRuntimeProvider<T>(
209
+ label: string,
210
+ fn: () => MaybePromise<T>,
211
+ ): Promise<T> {
212
+ try {
213
+ return await fn();
214
+ } catch (error) {
215
+ throw new ConnectError(
216
+ `plugin runtime provider ${label}: ${errorMessage(error)}`,
217
+ Code.Unknown,
218
+ );
219
+ }
220
+ }
@@ -38,6 +38,12 @@ const PROVIDER_KIND_DEFINITIONS = {
38
38
  defaultExportNames: ["s3", "provider"],
39
39
  label: "s3 provider",
40
40
  },
41
+ runtime: {
42
+ tokens: ["runtime"],
43
+ formatToken: "runtime",
44
+ defaultExportNames: ["runtime", "provider"],
45
+ label: "runtime provider",
46
+ },
41
47
  workflow: {
42
48
  tokens: ["workflow"],
43
49
  formatToken: "workflow",
package/src/provider.ts CHANGED
@@ -9,6 +9,7 @@ export type ProviderKind =
9
9
  | "cache"
10
10
  | "secrets"
11
11
  | "s3"
12
+ | "runtime"
12
13
  | "workflow"
13
14
  | "agent"
14
15
  | "telemetry";
@@ -42,6 +43,12 @@ export type HealthCheckHandler = () => MaybePromise<void>;
42
43
  */
43
44
  export type WarningsHandler = () => MaybePromise<string[]>;
44
45
 
46
+ /**
47
+ * Optional hook invoked after configuration when the host is ready for
48
+ * provider-owned background work to begin.
49
+ */
50
+ export type StartHandler = () => MaybePromise<void>;
51
+
45
52
  /**
46
53
  * Optional shutdown hook invoked when the provider process exits.
47
54
  */
@@ -58,6 +65,7 @@ export interface RuntimeProviderOptions {
58
65
  configure?: ConfigureHandler;
59
66
  healthCheck?: HealthCheckHandler;
60
67
  warnings?: string[] | WarningsHandler;
68
+ start?: StartHandler;
61
69
  close?: CloseHandler;
62
70
  }
63
71
 
@@ -75,6 +83,7 @@ export abstract class RuntimeProvider {
75
83
  private readonly configureHandler: ConfigureHandler | undefined;
76
84
  private readonly healthCheckHandler: HealthCheckHandler | undefined;
77
85
  private readonly warningsSource: string[] | WarningsHandler | undefined;
86
+ private readonly startHandler: StartHandler | undefined;
78
87
  private readonly closeHandler: CloseHandler | undefined;
79
88
 
80
89
  protected constructor(options: RuntimeProviderOptions) {
@@ -87,6 +96,7 @@ export abstract class RuntimeProvider {
87
96
  this.warningsSource = Array.isArray(options.warnings)
88
97
  ? [...options.warnings]
89
98
  : options.warnings;
99
+ this.startHandler = options.start;
90
100
  this.closeHandler = options.close;
91
101
  }
92
102
 
@@ -127,6 +137,10 @@ export abstract class RuntimeProvider {
127
137
  await this.healthCheckHandler?.();
128
138
  }
129
139
 
140
+ async startProvider(): Promise<void> {
141
+ await this.startHandler?.();
142
+ }
143
+
130
144
  async warnings(): Promise<string[]> {
131
145
  if (!this.warningsSource) {
132
146
  return [];
@@ -159,6 +173,8 @@ export function isRuntimeProvider(value: unknown): value is RuntimeProvider {
159
173
  typeof (value as { supportsHealthCheck?: unknown }).supportsHealthCheck === "function" &&
160
174
  "healthCheck" in value &&
161
175
  typeof (value as { healthCheck?: unknown }).healthCheck === "function" &&
176
+ "startProvider" in value &&
177
+ typeof (value as { startProvider?: unknown }).startProvider === "function" &&
162
178
  "warnings" in value &&
163
179
  typeof (value as { warnings?: unknown }).warnings === "function" &&
164
180
  "closeProvider" in value &&