@valon-technologies/gestalt 0.0.1-alpha.12 → 0.0.1-alpha.14
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/README.md +1 -1
- package/gen/google/rpc/status_pb.ts +76 -0
- package/gen/v1/agent_pb.ts +2412 -0
- package/gen/v1/authentication_pb.ts +1 -1
- package/gen/v1/authorization_pb.ts +28 -28
- package/gen/v1/cache_pb.ts +4 -4
- package/gen/v1/datastore_pb.ts +467 -12
- package/gen/v1/external_credential_pb.ts +274 -0
- package/gen/v1/plugin_pb.ts +64 -42
- package/gen/v1/pluginruntime_pb.ts +632 -0
- package/gen/v1/runtime_pb.ts +46 -3
- package/gen/v1/s3_pb.ts +120 -20
- package/gen/v1/secrets_pb.ts +1 -1
- package/gen/v1/workflow_pb.ts +849 -97
- package/package.json +5 -3
- package/src/agent-manager.ts +247 -0
- package/src/agent.ts +645 -0
- package/src/api.ts +4 -1
- package/src/authorization.ts +88 -18
- package/src/index.ts +134 -16
- package/src/indexeddb.ts +481 -1
- package/src/invoker.ts +3 -0
- package/src/plugin.ts +81 -181
- package/src/pluginruntime.ts +220 -0
- package/src/provider-kind.ts +12 -0
- package/src/provider.ts +28 -1
- package/src/runtime-log-host.ts +244 -0
- package/src/runtime.ts +194 -67
- package/src/s3.ts +170 -38
- package/src/telemetry.ts +429 -0
- package/src/workflow-manager.ts +78 -9
- package/src/manifest-metadata.ts +0 -106
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { connect } from "node:net";
|
|
2
|
+
import { Writable } from "node:stream";
|
|
3
|
+
|
|
4
|
+
import type { MessageInitShape } from "@bufbuild/protobuf";
|
|
5
|
+
import {
|
|
6
|
+
createClient,
|
|
7
|
+
type Client,
|
|
8
|
+
type Interceptor,
|
|
9
|
+
} from "@connectrpc/connect";
|
|
10
|
+
import { createGrpcTransport } from "@connectrpc/connect-node";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
AppendPluginRuntimeLogsRequestSchema,
|
|
14
|
+
type AppendPluginRuntimeLogsResponse,
|
|
15
|
+
PluginRuntimeLogHost as PluginRuntimeLogHostService,
|
|
16
|
+
PluginRuntimeLogStream,
|
|
17
|
+
} from "../gen/v1/pluginruntime_pb.ts";
|
|
18
|
+
|
|
19
|
+
export const ENV_RUNTIME_LOG_HOST_SOCKET = "GESTALT_RUNTIME_LOG_SOCKET";
|
|
20
|
+
export const ENV_RUNTIME_LOG_HOST_SOCKET_TOKEN = `${ENV_RUNTIME_LOG_HOST_SOCKET}_TOKEN`;
|
|
21
|
+
export const ENV_RUNTIME_SESSION_ID = "GESTALT_RUNTIME_SESSION_ID";
|
|
22
|
+
|
|
23
|
+
const RUNTIME_LOG_RELAY_TOKEN_HEADER = "x-gestalt-host-service-relay-token";
|
|
24
|
+
|
|
25
|
+
export type RuntimeLogStreamName = "stdout" | "stderr" | "runtime";
|
|
26
|
+
export type RuntimeLogStreamInput =
|
|
27
|
+
| RuntimeLogStreamName
|
|
28
|
+
| PluginRuntimeLogStream;
|
|
29
|
+
export type RuntimeLogAppendLogsInput = MessageInitShape<
|
|
30
|
+
typeof AppendPluginRuntimeLogsRequestSchema
|
|
31
|
+
>;
|
|
32
|
+
export type RuntimeLogAppendResponseMessage = AppendPluginRuntimeLogsResponse;
|
|
33
|
+
|
|
34
|
+
export interface RuntimeLogAppendInput {
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
message: string | Uint8Array;
|
|
37
|
+
stream?: RuntimeLogStreamInput;
|
|
38
|
+
observedAt?: Date;
|
|
39
|
+
sourceSeq?: number | bigint;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface RuntimeLogWriterOptions {
|
|
43
|
+
sessionId?: string;
|
|
44
|
+
stream?: RuntimeLogStreamInput;
|
|
45
|
+
sourceSeqStart?: number | bigint;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class RuntimeLogHost {
|
|
49
|
+
private readonly client: Client<typeof PluginRuntimeLogHostService>;
|
|
50
|
+
private sourceSeq = 0n;
|
|
51
|
+
|
|
52
|
+
constructor() {
|
|
53
|
+
const target = process.env[ENV_RUNTIME_LOG_HOST_SOCKET];
|
|
54
|
+
if (!target) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`runtime log host: ${ENV_RUNTIME_LOG_HOST_SOCKET} is not set`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const relayToken =
|
|
60
|
+
process.env[ENV_RUNTIME_LOG_HOST_SOCKET_TOKEN]?.trim() ?? "";
|
|
61
|
+
const transportOptions = runtimeLogTransportOptions(target);
|
|
62
|
+
const transport = createGrpcTransport({
|
|
63
|
+
...transportOptions,
|
|
64
|
+
...(transportOptions.nodeOptions
|
|
65
|
+
? {
|
|
66
|
+
nodeOptions: {
|
|
67
|
+
createConnection: () =>
|
|
68
|
+
connect(transportOptions.nodeOptions!.path),
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
: {}),
|
|
72
|
+
interceptors: relayToken
|
|
73
|
+
? [runtimeLogRelayTokenInterceptor(relayToken)]
|
|
74
|
+
: [],
|
|
75
|
+
});
|
|
76
|
+
this.client = createClient(PluginRuntimeLogHostService, transport);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async appendLogs(
|
|
80
|
+
request: RuntimeLogAppendLogsInput,
|
|
81
|
+
): Promise<RuntimeLogAppendResponseMessage> {
|
|
82
|
+
return await this.client.appendLogs(request);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async append(
|
|
86
|
+
input: RuntimeLogAppendInput,
|
|
87
|
+
): Promise<RuntimeLogAppendResponseMessage> {
|
|
88
|
+
const sourceSeq =
|
|
89
|
+
input.sourceSeq === undefined
|
|
90
|
+
? (this.sourceSeq += 1n)
|
|
91
|
+
: BigInt(input.sourceSeq);
|
|
92
|
+
if (sourceSeq > this.sourceSeq) {
|
|
93
|
+
this.sourceSeq = sourceSeq;
|
|
94
|
+
}
|
|
95
|
+
return await this.appendLogs({
|
|
96
|
+
sessionId: runtimeSessionId(input.sessionId),
|
|
97
|
+
logs: [
|
|
98
|
+
{
|
|
99
|
+
stream: runtimeLogStream(input.stream ?? "runtime"),
|
|
100
|
+
message: runtimeLogMessage(input.message),
|
|
101
|
+
observedAt: toProtoTimestamp(input.observedAt ?? new Date()),
|
|
102
|
+
sourceSeq,
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
writer(options?: RuntimeLogWriterOptions): Writable;
|
|
109
|
+
writer(sessionId: string, options?: RuntimeLogWriterOptions): Writable;
|
|
110
|
+
writer(
|
|
111
|
+
sessionIdOrOptions: string | RuntimeLogWriterOptions = {},
|
|
112
|
+
options: RuntimeLogWriterOptions = {},
|
|
113
|
+
): Writable {
|
|
114
|
+
const writerOptions =
|
|
115
|
+
typeof sessionIdOrOptions === "string"
|
|
116
|
+
? options
|
|
117
|
+
: sessionIdOrOptions;
|
|
118
|
+
const sessionId = runtimeSessionId(
|
|
119
|
+
typeof sessionIdOrOptions === "string"
|
|
120
|
+
? sessionIdOrOptions
|
|
121
|
+
: writerOptions.sessionId,
|
|
122
|
+
);
|
|
123
|
+
const stream = writerOptions.stream ?? "stdout";
|
|
124
|
+
let sourceSeq = BigInt(writerOptions.sourceSeqStart ?? 0);
|
|
125
|
+
|
|
126
|
+
return new Writable({
|
|
127
|
+
write: (chunk: Buffer | string, encoding, callback) => {
|
|
128
|
+
const actualEncoding = (
|
|
129
|
+
String(encoding) === "buffer" ? "utf8" : encoding
|
|
130
|
+
) as BufferEncoding;
|
|
131
|
+
const message =
|
|
132
|
+
typeof chunk === "string"
|
|
133
|
+
? chunk
|
|
134
|
+
: Buffer.from(chunk).toString(actualEncoding);
|
|
135
|
+
sourceSeq += 1n;
|
|
136
|
+
this.append({
|
|
137
|
+
sessionId,
|
|
138
|
+
stream,
|
|
139
|
+
message,
|
|
140
|
+
sourceSeq,
|
|
141
|
+
}).then(
|
|
142
|
+
() => callback(),
|
|
143
|
+
(error: unknown) => callback(toError(error)),
|
|
144
|
+
);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function runtimeSessionId(sessionId?: string): string {
|
|
151
|
+
const value = (sessionId ?? process.env[ENV_RUNTIME_SESSION_ID] ?? "").trim();
|
|
152
|
+
if (!value) {
|
|
153
|
+
throw new Error(`runtime session: ${ENV_RUNTIME_SESSION_ID} is not set`);
|
|
154
|
+
}
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function runtimeLogTransportOptions(rawTarget: string): {
|
|
159
|
+
baseUrl: string;
|
|
160
|
+
nodeOptions?: { path: string };
|
|
161
|
+
} {
|
|
162
|
+
const target = rawTarget.trim();
|
|
163
|
+
if (!target) {
|
|
164
|
+
throw new Error("runtime log host: transport target is required");
|
|
165
|
+
}
|
|
166
|
+
if (target.startsWith("tcp://")) {
|
|
167
|
+
const address = target.slice("tcp://".length).trim();
|
|
168
|
+
if (!address) {
|
|
169
|
+
throw new Error(
|
|
170
|
+
`runtime log host: tcp target ${JSON.stringify(rawTarget)} is missing host:port`,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return { baseUrl: `http://${address}` };
|
|
174
|
+
}
|
|
175
|
+
if (target.startsWith("tls://")) {
|
|
176
|
+
const address = target.slice("tls://".length).trim();
|
|
177
|
+
if (!address) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`runtime log host: tls target ${JSON.stringify(rawTarget)} is missing host:port`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
return { baseUrl: `https://${address}` };
|
|
183
|
+
}
|
|
184
|
+
if (target.startsWith("unix://")) {
|
|
185
|
+
const socketPath = target.slice("unix://".length).trim();
|
|
186
|
+
if (!socketPath) {
|
|
187
|
+
throw new Error(
|
|
188
|
+
`runtime log host: unix target ${JSON.stringify(rawTarget)} is missing a socket path`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
return { baseUrl: "http://localhost", nodeOptions: { path: socketPath } };
|
|
192
|
+
}
|
|
193
|
+
if (target.includes("://")) {
|
|
194
|
+
const parsed = new URL(target);
|
|
195
|
+
throw new Error(
|
|
196
|
+
`runtime log host: unsupported target scheme ${JSON.stringify(parsed.protocol.replace(/:$/, ""))}`,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return { baseUrl: "http://localhost", nodeOptions: { path: target } };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function runtimeLogRelayTokenInterceptor(token: string): Interceptor {
|
|
203
|
+
return (next) => async (req) => {
|
|
204
|
+
req.header.set(RUNTIME_LOG_RELAY_TOKEN_HEADER, token);
|
|
205
|
+
return await next(req);
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function runtimeLogStream(stream: RuntimeLogStreamInput): PluginRuntimeLogStream {
|
|
210
|
+
if (typeof stream === "number") {
|
|
211
|
+
return stream;
|
|
212
|
+
}
|
|
213
|
+
switch (stream.trim().toLowerCase()) {
|
|
214
|
+
case "stdout":
|
|
215
|
+
return PluginRuntimeLogStream.STDOUT;
|
|
216
|
+
case "stderr":
|
|
217
|
+
return PluginRuntimeLogStream.STDERR;
|
|
218
|
+
case "runtime":
|
|
219
|
+
return PluginRuntimeLogStream.RUNTIME;
|
|
220
|
+
default:
|
|
221
|
+
throw new Error(`unsupported runtime log stream ${JSON.stringify(stream)}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function runtimeLogMessage(message: string | Uint8Array): string {
|
|
226
|
+
if (typeof message === "string") {
|
|
227
|
+
return message;
|
|
228
|
+
}
|
|
229
|
+
return Buffer.from(message).toString("utf8");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function toProtoTimestamp(value: Date): { seconds: bigint; nanos: number } {
|
|
233
|
+
const millis = value.getTime();
|
|
234
|
+
const seconds = Math.floor(millis / 1000);
|
|
235
|
+
const nanos = Math.trunc((millis - (seconds * 1000)) * 1_000_000);
|
|
236
|
+
return {
|
|
237
|
+
seconds: BigInt(seconds),
|
|
238
|
+
nanos,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function toError(error: unknown): Error {
|
|
243
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
244
|
+
}
|
package/src/runtime.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { createServer } from "node:http2";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
|
|
@@ -12,6 +12,9 @@ import {
|
|
|
12
12
|
} from "@connectrpc/connect";
|
|
13
13
|
import { connectNodeAdapter } from "@connectrpc/connect-node";
|
|
14
14
|
|
|
15
|
+
import {
|
|
16
|
+
AgentProvider as AgentProviderService,
|
|
17
|
+
} from "../gen/v1/agent_pb.ts";
|
|
15
18
|
import {
|
|
16
19
|
AuthenticationProvider as AuthenticationProviderService,
|
|
17
20
|
AuthSessionSettingsSchema,
|
|
@@ -40,10 +43,12 @@ import {
|
|
|
40
43
|
CatalogSchema as ProtoCatalogSchema,
|
|
41
44
|
ConnectionMode as ProviderConnectionMode,
|
|
42
45
|
GetSessionCatalogResponseSchema,
|
|
46
|
+
PostConnectResponseSchema,
|
|
43
47
|
ResolveHTTPSubjectResponseSchema,
|
|
44
48
|
OperationResultSchema,
|
|
45
49
|
ProviderMetadataSchema,
|
|
46
50
|
type HTTPSubjectRequest as ProtoHTTPSubjectRequest,
|
|
51
|
+
type PostConnectCredential as ProtoPostConnectCredential,
|
|
47
52
|
type RequestContext as ProtoRequestContext,
|
|
48
53
|
type ResolveHTTPSubjectRequest as ProtoResolveHTTPSubjectRequest,
|
|
49
54
|
IntegrationProvider as IntegrationProviderService,
|
|
@@ -52,17 +57,26 @@ import {
|
|
|
52
57
|
type GetSessionCatalogRequest,
|
|
53
58
|
type StartProviderRequest,
|
|
54
59
|
} from "../gen/v1/plugin_pb.ts";
|
|
60
|
+
import {
|
|
61
|
+
PluginRuntimeProvider as PluginRuntimeProviderService,
|
|
62
|
+
} from "../gen/v1/pluginruntime_pb.ts";
|
|
55
63
|
import {
|
|
56
64
|
ConfigureProviderResponseSchema,
|
|
57
65
|
HealthCheckResponseSchema,
|
|
58
66
|
ProviderIdentitySchema,
|
|
59
67
|
ProviderKind as ProtoProviderKind,
|
|
60
68
|
ProviderLifecycle,
|
|
69
|
+
StartRuntimeProviderResponseSchema,
|
|
61
70
|
type ConfigureProviderRequest,
|
|
62
71
|
} from "../gen/v1/runtime_pb.ts";
|
|
63
72
|
import { S3 as S3Service } from "../gen/v1/s3_pb.ts";
|
|
64
73
|
import { WorkflowProvider as WorkflowProviderService } from "../gen/v1/workflow_pb.ts";
|
|
65
74
|
import { errorMessage, type Request } from "./api.ts";
|
|
75
|
+
import {
|
|
76
|
+
AgentProvider,
|
|
77
|
+
createAgentProviderService,
|
|
78
|
+
isAgentProvider,
|
|
79
|
+
} from "./agent.ts";
|
|
66
80
|
import {
|
|
67
81
|
AuthenticationProvider,
|
|
68
82
|
isAuthenticationProvider,
|
|
@@ -77,11 +91,17 @@ import {
|
|
|
77
91
|
type HTTPSubjectResolutionContext,
|
|
78
92
|
} from "./http-subject.ts";
|
|
79
93
|
import {
|
|
94
|
+
type ConnectedToken,
|
|
80
95
|
PluginProvider,
|
|
81
96
|
connectionModeToProtoValue,
|
|
82
97
|
connectionParamToProto,
|
|
83
98
|
isPluginProvider,
|
|
84
99
|
} from "./plugin.ts";
|
|
100
|
+
import {
|
|
101
|
+
PluginRuntimeProvider,
|
|
102
|
+
createPluginRuntimeProviderService,
|
|
103
|
+
isPluginRuntimeProvider,
|
|
104
|
+
} from "./pluginruntime.ts";
|
|
85
105
|
import {
|
|
86
106
|
providerKindLabel,
|
|
87
107
|
resolveDefaultProviderExport,
|
|
@@ -114,11 +134,6 @@ export const ENV_PROVIDER_PARENT_PID = "GESTALT_PLUGIN_PARENT_PID";
|
|
|
114
134
|
* Environment variable used to request static catalog generation.
|
|
115
135
|
*/
|
|
116
136
|
export const ENV_WRITE_CATALOG = "GESTALT_PLUGIN_WRITE_CATALOG";
|
|
117
|
-
/**
|
|
118
|
-
* Environment variable used to request generated manifest metadata export.
|
|
119
|
-
*/
|
|
120
|
-
export const ENV_WRITE_MANIFEST_METADATA =
|
|
121
|
-
"GESTALT_PLUGIN_WRITE_MANIFEST_METADATA";
|
|
122
137
|
/**
|
|
123
138
|
* Protocol version currently implemented by the TypeScript runtime.
|
|
124
139
|
*/
|
|
@@ -127,6 +142,8 @@ export const CURRENT_PROTOCOL_VERSION = 3;
|
|
|
127
142
|
* Command-line usage for the runtime entrypoint.
|
|
128
143
|
*/
|
|
129
144
|
export const USAGE = "usage: bun run runtime.ts ROOT PROVIDER_TARGET";
|
|
145
|
+
export { createAgentProviderService } from "./agent.ts";
|
|
146
|
+
export { createPluginRuntimeProviderService } from "./pluginruntime.ts";
|
|
130
147
|
export { createWorkflowProviderService } from "./workflow.ts";
|
|
131
148
|
|
|
132
149
|
/**
|
|
@@ -146,6 +163,8 @@ export type LoadedProvider =
|
|
|
146
163
|
| CacheProvider
|
|
147
164
|
| SecretsProvider
|
|
148
165
|
| S3Provider
|
|
166
|
+
| PluginRuntimeProvider
|
|
167
|
+
| AgentProvider
|
|
149
168
|
| WorkflowProvider;
|
|
150
169
|
|
|
151
170
|
type ProviderRuntimeEntry = {
|
|
@@ -205,6 +224,27 @@ const PROVIDER_RUNTIME_ENTRIES: Partial<
|
|
|
205
224
|
router.service(S3Service, createS3Service(provider as S3Provider));
|
|
206
225
|
},
|
|
207
226
|
},
|
|
227
|
+
runtime: {
|
|
228
|
+
isProvider:
|
|
229
|
+
isPluginRuntimeProvider as (value: unknown) => value is LoadedProvider,
|
|
230
|
+
protoKind: ProtoProviderKind.RUNTIME,
|
|
231
|
+
registerService(router, provider) {
|
|
232
|
+
router.service(
|
|
233
|
+
PluginRuntimeProviderService,
|
|
234
|
+
createPluginRuntimeProviderService(provider as PluginRuntimeProvider),
|
|
235
|
+
);
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
agent: {
|
|
239
|
+
isProvider: isAgentProvider as (value: unknown) => value is LoadedProvider,
|
|
240
|
+
protoKind: ProtoProviderKind.AGENT,
|
|
241
|
+
registerService(router, provider) {
|
|
242
|
+
router.service(
|
|
243
|
+
AgentProviderService,
|
|
244
|
+
createAgentProviderService(provider as AgentProvider),
|
|
245
|
+
);
|
|
246
|
+
},
|
|
247
|
+
},
|
|
208
248
|
workflow: {
|
|
209
249
|
isProvider: isWorkflowProvider as (value: unknown) => value is LoadedProvider,
|
|
210
250
|
protoKind: ProtoProviderKind.WORKFLOW,
|
|
@@ -301,19 +341,11 @@ export async function runLoadedProvider(
|
|
|
301
341
|
}
|
|
302
342
|
|
|
303
343
|
const catalogPath = process.env[ENV_WRITE_CATALOG];
|
|
304
|
-
|
|
305
|
-
if (catalogPath || manifestMetadataPath) {
|
|
344
|
+
if (catalogPath) {
|
|
306
345
|
if (!isPluginProvider(provider)) {
|
|
307
|
-
throw new Error(
|
|
308
|
-
"static catalog and manifest metadata generation are only supported for plugin providers",
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
if (catalogPath) {
|
|
312
|
-
writeFileSync(catalogPath, catalogToYaml(provider.staticCatalog()), "utf8");
|
|
313
|
-
}
|
|
314
|
-
if (manifestMetadataPath && provider.supportsManifestMetadata()) {
|
|
315
|
-
provider.writeManifestMetadata(manifestMetadataPath);
|
|
346
|
+
throw new Error("static catalog generation is only supported for plugin providers");
|
|
316
347
|
}
|
|
348
|
+
writeFileSync(catalogPath, catalogToYaml(provider.staticCatalog()), "utf8");
|
|
317
349
|
return;
|
|
318
350
|
}
|
|
319
351
|
|
|
@@ -341,9 +373,7 @@ export async function serve(provider: LoadedProvider): Promise<void> {
|
|
|
341
373
|
if (!socketPath) {
|
|
342
374
|
throw new Error(`${ENV_PROVIDER_SOCKET} is required`);
|
|
343
375
|
}
|
|
344
|
-
|
|
345
|
-
rmSync(socketPath);
|
|
346
|
-
}
|
|
376
|
+
rmSync(socketPath, { force: true });
|
|
347
377
|
|
|
348
378
|
const handler = connectNodeAdapter({
|
|
349
379
|
grpc: true,
|
|
@@ -370,9 +400,7 @@ export async function serve(provider: LoadedProvider): Promise<void> {
|
|
|
370
400
|
server.close(() => resolveClose());
|
|
371
401
|
});
|
|
372
402
|
} finally {
|
|
373
|
-
|
|
374
|
-
rmSync(socketPath);
|
|
375
|
-
}
|
|
403
|
+
rmSync(socketPath, { force: true });
|
|
376
404
|
}
|
|
377
405
|
}
|
|
378
406
|
})();
|
|
@@ -412,16 +440,20 @@ export function createRuntimeService(
|
|
|
412
440
|
): Partial<ServiceImpl<typeof ProviderLifecycle>> {
|
|
413
441
|
return {
|
|
414
442
|
async getProviderIdentity() {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
443
|
+
try {
|
|
444
|
+
return create(ProviderIdentitySchema, {
|
|
445
|
+
kind: providerRuntimeEntry(provider.kind).protoKind,
|
|
446
|
+
name: provider.name,
|
|
447
|
+
displayName: provider.displayName,
|
|
448
|
+
description: provider.description,
|
|
449
|
+
version: provider.version,
|
|
450
|
+
warnings: await provider.warnings(),
|
|
451
|
+
minProtocolVersion: CURRENT_PROTOCOL_VERSION,
|
|
452
|
+
maxProtocolVersion: CURRENT_PROTOCOL_VERSION,
|
|
453
|
+
});
|
|
454
|
+
} catch (error) {
|
|
455
|
+
throw providerRuntimeError("provider identity", error);
|
|
456
|
+
}
|
|
425
457
|
},
|
|
426
458
|
async configureProvider(request: ConfigureProviderRequest) {
|
|
427
459
|
assertProtocolVersion(request.protocolVersion);
|
|
@@ -431,10 +463,7 @@ export function createRuntimeService(
|
|
|
431
463
|
objectFromUnknown(request.config),
|
|
432
464
|
);
|
|
433
465
|
} catch (error) {
|
|
434
|
-
throw
|
|
435
|
-
`configure provider: ${errorMessage(error)}`,
|
|
436
|
-
Code.Unknown,
|
|
437
|
-
);
|
|
466
|
+
throw providerRuntimeError("configure provider", error);
|
|
438
467
|
}
|
|
439
468
|
return create(ConfigureProviderResponseSchema, {
|
|
440
469
|
protocolVersion: CURRENT_PROTOCOL_VERSION,
|
|
@@ -458,6 +487,16 @@ export function createRuntimeService(
|
|
|
458
487
|
});
|
|
459
488
|
}
|
|
460
489
|
},
|
|
490
|
+
async startProvider() {
|
|
491
|
+
try {
|
|
492
|
+
await provider.startProvider();
|
|
493
|
+
} catch (error) {
|
|
494
|
+
throw providerRuntimeError("start provider", error);
|
|
495
|
+
}
|
|
496
|
+
return create(StartRuntimeProviderResponseSchema, {
|
|
497
|
+
protocolVersion: CURRENT_PROTOCOL_VERSION,
|
|
498
|
+
});
|
|
499
|
+
},
|
|
461
500
|
};
|
|
462
501
|
}
|
|
463
502
|
|
|
@@ -473,27 +512,31 @@ export function createProviderService(
|
|
|
473
512
|
throw new Error("provider is not a plugin provider");
|
|
474
513
|
}
|
|
475
514
|
return {
|
|
476
|
-
getMetadata() {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
Object.
|
|
487
|
-
key,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
515
|
+
async getMetadata() {
|
|
516
|
+
try {
|
|
517
|
+
return create(ProviderMetadataSchema, {
|
|
518
|
+
name: provider.name,
|
|
519
|
+
displayName: provider.displayName,
|
|
520
|
+
description: provider.description,
|
|
521
|
+
connectionMode: connectionModeToProtoValue(
|
|
522
|
+
provider.connectionMode,
|
|
523
|
+
) as ProviderConnectionMode,
|
|
524
|
+
authTypes: [...provider.authTypes],
|
|
525
|
+
connectionParams: Object.fromEntries(
|
|
526
|
+
Object.entries(provider.connectionParams).map(([key, value]) => [
|
|
527
|
+
key,
|
|
528
|
+
connectionParamToProto(value),
|
|
529
|
+
]),
|
|
530
|
+
),
|
|
531
|
+
staticCatalog: catalogToProto(provider.staticCatalog()),
|
|
532
|
+
supportsSessionCatalog: provider.supportsSessionCatalog(),
|
|
533
|
+
supportsPostConnect: provider.supportsPostConnect(),
|
|
534
|
+
minProtocolVersion: CURRENT_PROTOCOL_VERSION,
|
|
535
|
+
maxProtocolVersion: CURRENT_PROTOCOL_VERSION,
|
|
536
|
+
});
|
|
537
|
+
} catch (error) {
|
|
538
|
+
throw providerRuntimeError("provider metadata", error);
|
|
539
|
+
}
|
|
497
540
|
},
|
|
498
541
|
async startProvider(request: StartProviderRequest) {
|
|
499
542
|
assertProtocolVersion(request.protocolVersion);
|
|
@@ -503,10 +546,7 @@ export function createProviderService(
|
|
|
503
546
|
objectFromUnknown(request.config),
|
|
504
547
|
);
|
|
505
548
|
} catch (error) {
|
|
506
|
-
throw
|
|
507
|
-
`configure provider: ${errorMessage(error)}`,
|
|
508
|
-
Code.Unknown,
|
|
509
|
-
);
|
|
549
|
+
throw providerRuntimeError("configure provider", error);
|
|
510
550
|
}
|
|
511
551
|
return create(StartProviderResponseSchema, {
|
|
512
552
|
protocolVersion: CURRENT_PROTOCOL_VERSION,
|
|
@@ -523,6 +563,7 @@ export function createProviderService(
|
|
|
523
563
|
request.connectionParams,
|
|
524
564
|
request.context,
|
|
525
565
|
request.invocationToken,
|
|
566
|
+
request.idempotencyKey,
|
|
526
567
|
),
|
|
527
568
|
),
|
|
528
569
|
);
|
|
@@ -583,11 +624,29 @@ export function createProviderService(
|
|
|
583
624
|
catalog: catalogToProto(catalog),
|
|
584
625
|
});
|
|
585
626
|
},
|
|
586
|
-
async postConnect() {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
627
|
+
async postConnect(request) {
|
|
628
|
+
if (!provider.supportsPostConnect()) {
|
|
629
|
+
throw new ConnectError(
|
|
630
|
+
"provider does not support post connect",
|
|
631
|
+
Code.Unimplemented,
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
let metadata: Record<string, string> | null | undefined;
|
|
635
|
+
try {
|
|
636
|
+
metadata = await provider.postConnectMetadata(
|
|
637
|
+
providerConnectedToken(request.token),
|
|
638
|
+
);
|
|
639
|
+
} catch (error) {
|
|
640
|
+
throw new ConnectError(
|
|
641
|
+
`post connect: ${errorMessage(error)}`,
|
|
642
|
+
Code.Unknown,
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
return create(PostConnectResponseSchema, {
|
|
646
|
+
metadata: {
|
|
647
|
+
...(metadata ?? {}),
|
|
648
|
+
},
|
|
649
|
+
});
|
|
591
650
|
},
|
|
592
651
|
};
|
|
593
652
|
}
|
|
@@ -758,6 +817,7 @@ function providerRequest(
|
|
|
758
817
|
connectionParams: Record<string, string>,
|
|
759
818
|
requestContext?: ProtoRequestContext,
|
|
760
819
|
invocationToken = "",
|
|
820
|
+
idempotencyKey = "",
|
|
761
821
|
): Request {
|
|
762
822
|
const subject = requestContext?.subject;
|
|
763
823
|
const credential = requestContext?.credential;
|
|
@@ -787,6 +847,7 @@ function providerRequest(
|
|
|
787
847
|
...(requestContext?.workflow ?? {}),
|
|
788
848
|
},
|
|
789
849
|
invocationToken,
|
|
850
|
+
idempotencyKey: idempotencyKey.trim(),
|
|
790
851
|
};
|
|
791
852
|
}
|
|
792
853
|
|
|
@@ -822,6 +883,29 @@ function providerHTTPSubjectResolutionContext(
|
|
|
822
883
|
};
|
|
823
884
|
}
|
|
824
885
|
|
|
886
|
+
function providerConnectedToken(
|
|
887
|
+
token?: ProtoPostConnectCredential,
|
|
888
|
+
): ConnectedToken {
|
|
889
|
+
const metadataJson = token?.metadataJson ?? "";
|
|
890
|
+
return {
|
|
891
|
+
id: token?.id ?? "",
|
|
892
|
+
subjectId: token?.subjectId ?? "",
|
|
893
|
+
integration: token?.integration ?? "",
|
|
894
|
+
connection: token?.connection ?? "",
|
|
895
|
+
instance: token?.instance ?? "",
|
|
896
|
+
accessToken: token?.accessToken ?? "",
|
|
897
|
+
refreshToken: token?.refreshToken ?? "",
|
|
898
|
+
scopes: token?.scopes ?? "",
|
|
899
|
+
expiresAt: timestampToDate(token?.expiresAt),
|
|
900
|
+
lastRefreshedAt: timestampToDate(token?.lastRefreshedAt),
|
|
901
|
+
refreshErrorCount: token?.refreshErrorCount ?? 0,
|
|
902
|
+
metadataJson,
|
|
903
|
+
metadata: stringRecordFromJSON(metadataJson),
|
|
904
|
+
createdAt: timestampToDate(token?.createdAt),
|
|
905
|
+
updatedAt: timestampToDate(token?.updatedAt),
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
|
|
825
909
|
function providerStringLists(
|
|
826
910
|
input: Record<string, { values?: string[] }> | undefined,
|
|
827
911
|
): Record<string, string[]> {
|
|
@@ -844,6 +928,10 @@ function providerRuntimeEntry(
|
|
|
844
928
|
return entry;
|
|
845
929
|
}
|
|
846
930
|
|
|
931
|
+
function providerRuntimeError(label: string, error: unknown): ConnectError {
|
|
932
|
+
return new ConnectError(`${label}: ${errorMessage(error)}`, Code.Unknown);
|
|
933
|
+
}
|
|
934
|
+
|
|
847
935
|
function resolveLoadedProvider(
|
|
848
936
|
candidate: unknown,
|
|
849
937
|
kind: ProviderKind,
|
|
@@ -930,6 +1018,45 @@ function normalizeBigInt(value: number | bigint): bigint {
|
|
|
930
1018
|
return BigInt(Math.max(0, Math.trunc(value)));
|
|
931
1019
|
}
|
|
932
1020
|
|
|
1021
|
+
function timestampToDate(
|
|
1022
|
+
value: { seconds: bigint; nanos: number } | undefined,
|
|
1023
|
+
): Date | undefined {
|
|
1024
|
+
if (!value) {
|
|
1025
|
+
return undefined;
|
|
1026
|
+
}
|
|
1027
|
+
const seconds = Number(value.seconds ?? 0n);
|
|
1028
|
+
const nanos = Number(value.nanos ?? 0);
|
|
1029
|
+
if (!Number.isFinite(seconds) || !Number.isFinite(nanos)) {
|
|
1030
|
+
return undefined;
|
|
1031
|
+
}
|
|
1032
|
+
const millis = (seconds * 1000) + Math.trunc(nanos / 1_000_000);
|
|
1033
|
+
if (!Number.isFinite(millis)) {
|
|
1034
|
+
return undefined;
|
|
1035
|
+
}
|
|
1036
|
+
return new Date(millis);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
function stringRecordFromJSON(value: string): Record<string, string> {
|
|
1040
|
+
if (!value.trim()) {
|
|
1041
|
+
return {};
|
|
1042
|
+
}
|
|
1043
|
+
try {
|
|
1044
|
+
const parsed = JSON.parse(value) as unknown;
|
|
1045
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
1046
|
+
return {};
|
|
1047
|
+
}
|
|
1048
|
+
const output: Record<string, string> = {};
|
|
1049
|
+
for (const [key, entry] of Object.entries(parsed)) {
|
|
1050
|
+
if (typeof entry === "string") {
|
|
1051
|
+
output[key] = entry;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
return output;
|
|
1055
|
+
} catch {
|
|
1056
|
+
return {};
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
933
1060
|
function cloneUint8Array(value: Uint8Array | undefined): Uint8Array {
|
|
934
1061
|
if (!value) {
|
|
935
1062
|
return new Uint8Array();
|