@valon-technologies/gestalt 0.0.1-alpha.18 → 0.0.1-alpha.20

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.
@@ -0,0 +1,19 @@
1
+ import type { JsonObject } from "@bufbuild/protobuf";
2
+
3
+ import {
4
+ jsonObjectFromStruct,
5
+ structFromObject,
6
+ type JsonObjectInput,
7
+ } from "./protocol.ts";
8
+
9
+ export function optionalStruct(
10
+ value?: JsonObjectInput | undefined,
11
+ ): JsonObject | undefined {
12
+ return value === undefined ? undefined : structFromObject(value);
13
+ }
14
+
15
+ export function optionalObjectFromStruct(
16
+ value?: JsonObject | undefined,
17
+ ): JsonObjectInput | undefined {
18
+ return value === undefined ? undefined : jsonObjectFromStruct(value);
19
+ }
@@ -0,0 +1,186 @@
1
+ import {
2
+ create,
3
+ fromJson,
4
+ toJson,
5
+ type JsonObject,
6
+ type JsonValue,
7
+ } from "@bufbuild/protobuf";
8
+ import {
9
+ StructSchema,
10
+ TimestampSchema,
11
+ ValueSchema,
12
+ type Struct,
13
+ type Timestamp,
14
+ type Value,
15
+ } from "@bufbuild/protobuf/wkt";
16
+
17
+ const MIN_TIMESTAMP_SECONDS = -62_135_596_800n;
18
+ const MAX_TIMESTAMP_SECONDS = 253_402_300_799n;
19
+ const MIN_TIMESTAMP_SECONDS_NUMBER = Number(MIN_TIMESTAMP_SECONDS);
20
+ const MAX_TIMESTAMP_SECONDS_NUMBER = Number(MAX_TIMESTAMP_SECONDS);
21
+
22
+ /** Primitive values accepted in protobuf JSON payloads. */
23
+ export type JsonPrimitiveInput = null | boolean | number | string;
24
+ /** Native value accepted by SDK-owned protocol helpers before runtime validation. */
25
+ export type JsonInput = JsonPrimitiveInput | readonly unknown[] | object;
26
+ /** Native object accepted by SDK-owned Struct helpers before runtime validation. */
27
+ export type JsonObjectInput = object;
28
+ /** Alias for google.protobuf.Struct at protocol boundaries. */
29
+ export type { Struct };
30
+ /** Alias for google.protobuf.Value at protocol boundaries. */
31
+ export type { Value };
32
+ /** Alias for google.protobuf.Timestamp at protocol boundaries. */
33
+ export type { Timestamp };
34
+
35
+ /** Schema for google.protobuf.Struct. */
36
+ export { StructSchema };
37
+ /** Schema for google.protobuf.Value. */
38
+ export { ValueSchema };
39
+ /** Schema for google.protobuf.Timestamp. */
40
+ export { TimestampSchema };
41
+
42
+ /** Returns a protobuf Struct-compatible JSON object for generated message fields. */
43
+ export function structFromObject(value: JsonObjectInput = {}): JsonObject {
44
+ return normalizeJsonObject(value, "struct", new WeakSet<object>());
45
+ }
46
+
47
+ /** Returns a protobuf Struct-compatible JSON object for generated message fields. */
48
+ export function structFromJsonObject(value: JsonObject = {}): JsonObject {
49
+ return structFromObject(value);
50
+ }
51
+
52
+ /** Converts a protobuf Struct-compatible field value back to a JSON object. */
53
+ export function jsonObjectFromStruct(value?: JsonObject | undefined): JsonObject {
54
+ return value === undefined ? {} : { ...value };
55
+ }
56
+
57
+ /** Converts a JSON-compatible native value into a protobuf Value message. */
58
+ export function valueFromJson(value: JsonInput): Value {
59
+ return fromJson(ValueSchema, jsonFromInput(value));
60
+ }
61
+
62
+ /** Converts a protobuf Value message into its JSON value. */
63
+ export function jsonFromValue(value?: Value | undefined): JsonValue {
64
+ if (value === undefined) {
65
+ return null;
66
+ }
67
+ return toJson(ValueSchema, value);
68
+ }
69
+
70
+ /** Converts a valid JavaScript Date into a protobuf Timestamp message. */
71
+ export function timestampFromDate(value: Date): Timestamp {
72
+ const millis = value.getTime();
73
+ if (Number.isNaN(millis)) {
74
+ throw new TypeError("timestampFromDate expects a valid Date");
75
+ }
76
+ const seconds = Math.floor(millis / 1000);
77
+ if (
78
+ seconds < MIN_TIMESTAMP_SECONDS_NUMBER ||
79
+ seconds > MAX_TIMESTAMP_SECONDS_NUMBER
80
+ ) {
81
+ throw new RangeError("Date is outside the protobuf Timestamp range");
82
+ }
83
+ const nanos = Math.trunc((millis - (seconds * 1000)) * 1_000_000);
84
+ return create(TimestampSchema, {
85
+ seconds: BigInt(seconds),
86
+ nanos,
87
+ });
88
+ }
89
+
90
+ /** Converts a protobuf Timestamp message into a JavaScript Date. */
91
+ export function dateFromTimestamp(value: Timestamp): Date {
92
+ if (value.nanos < 0 || value.nanos >= 1_000_000_000) {
93
+ throw new RangeError("protobuf Timestamp nanos out of range");
94
+ }
95
+ if (
96
+ value.seconds < MIN_TIMESTAMP_SECONDS ||
97
+ value.seconds > MAX_TIMESTAMP_SECONDS
98
+ ) {
99
+ throw new RangeError("protobuf Timestamp seconds out of range");
100
+ }
101
+ const millis =
102
+ (Number(value.seconds) * 1000) + Math.trunc(value.nanos / 1_000_000);
103
+ const date = new Date(millis);
104
+ if (Number.isNaN(date.getTime())) {
105
+ throw new RangeError("protobuf Timestamp seconds out of range");
106
+ }
107
+ return date;
108
+ }
109
+
110
+ /** Returns a protobuf-compatible JSON value from native SDK input. */
111
+ export function jsonFromInput(value: JsonInput): JsonValue {
112
+ return normalizeJsonValue(value, "value", new WeakSet<object>());
113
+ }
114
+
115
+ function normalizeJsonObject(
116
+ value: unknown,
117
+ path: string,
118
+ seen: WeakSet<object>,
119
+ ): JsonObject {
120
+ if (!isPlainObject(value)) {
121
+ throw new TypeError(`${path} must be a plain JSON object`);
122
+ }
123
+ if (seen.has(value)) {
124
+ throw new TypeError(`${path} contains a cycle`);
125
+ }
126
+ seen.add(value);
127
+ try {
128
+ const output: JsonObject = {};
129
+ for (const key of Reflect.ownKeys(value)) {
130
+ if (typeof key !== "string") {
131
+ throw new TypeError(`${path} keys must be strings`);
132
+ }
133
+ }
134
+ for (const [key, entry] of Object.entries(value)) {
135
+ output[key] = normalizeJsonValue(entry, `${path}.${key}`, seen);
136
+ }
137
+ return output;
138
+ } finally {
139
+ seen.delete(value);
140
+ }
141
+ }
142
+
143
+ function normalizeJsonValue(
144
+ value: unknown,
145
+ path: string,
146
+ seen: WeakSet<object>,
147
+ ): JsonValue {
148
+ if (value === null) {
149
+ return null;
150
+ }
151
+ if (typeof value === "string" || typeof value === "boolean") {
152
+ return value;
153
+ }
154
+ if (typeof value === "number") {
155
+ if (!Number.isFinite(value)) {
156
+ throw new TypeError(`${path} must be a finite number`);
157
+ }
158
+ return value;
159
+ }
160
+ if (typeof value === "undefined") {
161
+ throw new TypeError(`${path} must not be undefined`);
162
+ }
163
+ if (typeof value === "bigint" || typeof value === "symbol" || typeof value === "function") {
164
+ throw new TypeError(`${path} must be JSON-compatible`);
165
+ }
166
+ if (Array.isArray(value)) {
167
+ if (seen.has(value)) {
168
+ throw new TypeError(`${path} contains a cycle`);
169
+ }
170
+ seen.add(value);
171
+ try {
172
+ return value.map((entry, index) => normalizeJsonValue(entry, `${path}[${index}]`, seen));
173
+ } finally {
174
+ seen.delete(value);
175
+ }
176
+ }
177
+ return normalizeJsonObject(value, path, seen);
178
+ }
179
+
180
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
181
+ if (value === null || typeof value !== "object") {
182
+ return false;
183
+ }
184
+ const prototype = Object.getPrototypeOf(value);
185
+ return prototype === Object.prototype || prototype === null;
186
+ }
@@ -20,6 +20,12 @@ const PROVIDER_KIND_DEFINITIONS = {
20
20
  defaultExportNames: ["authentication", "provider"],
21
21
  label: "authentication provider",
22
22
  },
23
+ authorization: {
24
+ tokens: ["authorization", "authz"],
25
+ formatToken: "authorization",
26
+ defaultExportNames: ["authorization", "provider"],
27
+ label: "authorization provider",
28
+ },
23
29
  cache: {
24
30
  tokens: ["cache"],
25
31
  formatToken: "cache",
@@ -72,9 +78,7 @@ const EXTERNAL_PROVIDER_KIND_TOKEN_SET = new Set<string>(
72
78
 
73
79
  const EXTERNAL_PROVIDER_KIND_MAP = new Map<string, ProviderKind>(
74
80
  Object.entries(PROVIDER_KIND_DEFINITIONS).flatMap(([kind, definition]) =>
75
- definition.tokens.map(
76
- (token) => [token, kind as ProviderKind] as const,
77
- ),
81
+ definition.tokens.map((token) => [token, kind as ProviderKind] as const),
78
82
  ),
79
83
  );
80
84
 
package/src/provider.ts CHANGED
@@ -6,6 +6,7 @@ import type { MaybePromise } from "./api.ts";
6
6
  export type ProviderKind =
7
7
  | "integration"
8
8
  | "authentication"
9
+ | "authorization"
9
10
  | "cache"
10
11
  | "secrets"
11
12
  | "s3"
@@ -55,9 +56,9 @@ export type StartHandler = () => MaybePromise<void>;
55
56
  export type CloseHandler = () => MaybePromise<void>;
56
57
 
57
58
  /**
58
- * Shared runtime metadata and lifecycle hooks for authored providers.
59
+ * Shared provider metadata and lifecycle hooks for authored providers.
59
60
  */
60
- export interface RuntimeProviderOptions {
61
+ export interface ProviderBaseOptions {
61
62
  name?: string;
62
63
  displayName?: string;
63
64
  description?: string;
@@ -72,7 +73,7 @@ export interface RuntimeProviderOptions {
72
73
  /**
73
74
  * Base class shared by all TypeScript SDK provider implementations.
74
75
  */
75
- export abstract class RuntimeProvider {
76
+ export abstract class ProviderBase {
76
77
  abstract readonly kind: ProviderKind;
77
78
 
78
79
  name: string;
@@ -86,7 +87,7 @@ export abstract class RuntimeProvider {
86
87
  private readonly startHandler: StartHandler | undefined;
87
88
  private readonly closeHandler: CloseHandler | undefined;
88
89
 
89
- protected constructor(options: RuntimeProviderOptions) {
90
+ protected constructor(options: ProviderBaseOptions) {
90
91
  this.name = slugName(options.name ?? "");
91
92
  this.displayName = options.displayName?.trim() ?? "";
92
93
  this.description = options.description?.trim() ?? "";
@@ -106,7 +107,7 @@ export abstract class RuntimeProvider {
106
107
  }
107
108
  }
108
109
 
109
- runtimeMetadata(): ProviderMetadata {
110
+ providerMetadata(): ProviderMetadata {
110
111
  const metadata: ProviderMetadata = {
111
112
  kind: this.kind,
112
113
  };
@@ -125,7 +126,10 @@ export abstract class RuntimeProvider {
125
126
  return metadata;
126
127
  }
127
128
 
128
- async configureProvider(name: string, config: Record<string, unknown>): Promise<void> {
129
+ async configureProvider(
130
+ name: string,
131
+ config: Record<string, unknown>,
132
+ ): Promise<void> {
129
133
  await this.configureHandler?.(name, config);
130
134
  }
131
135
 
@@ -157,28 +161,32 @@ export abstract class RuntimeProvider {
157
161
  }
158
162
 
159
163
  /**
160
- * Runtime type guard for values that implement the provider base contract.
164
+ * Type guard for values that implement the provider base contract.
161
165
  */
162
- export function isRuntimeProvider(value: unknown): value is RuntimeProvider {
166
+ export function isProviderBase(value: unknown): value is ProviderBase {
163
167
  return (
164
- value instanceof RuntimeProvider ||
168
+ value instanceof ProviderBase ||
165
169
  (typeof value === "object" &&
166
170
  value !== null &&
167
171
  "kind" in value &&
168
172
  "resolveName" in value &&
169
173
  typeof (value as { resolveName?: unknown }).resolveName === "function" &&
170
174
  "configureProvider" in value &&
171
- typeof (value as { configureProvider?: unknown }).configureProvider === "function" &&
175
+ typeof (value as { configureProvider?: unknown }).configureProvider ===
176
+ "function" &&
172
177
  "supportsHealthCheck" in value &&
173
- typeof (value as { supportsHealthCheck?: unknown }).supportsHealthCheck === "function" &&
178
+ typeof (value as { supportsHealthCheck?: unknown })
179
+ .supportsHealthCheck === "function" &&
174
180
  "healthCheck" in value &&
175
181
  typeof (value as { healthCheck?: unknown }).healthCheck === "function" &&
176
182
  "startProvider" in value &&
177
- typeof (value as { startProvider?: unknown }).startProvider === "function" &&
183
+ typeof (value as { startProvider?: unknown }).startProvider ===
184
+ "function" &&
178
185
  "warnings" in value &&
179
186
  typeof (value as { warnings?: unknown }).warnings === "function" &&
180
187
  "closeProvider" in value &&
181
- typeof (value as { closeProvider?: unknown }).closeProvider === "function")
188
+ typeof (value as { closeProvider?: unknown }).closeProvider ===
189
+ "function")
182
190
  );
183
191
  }
184
192
 
@@ -1,7 +1,6 @@
1
1
  import { connect } from "node:net";
2
2
  import { Writable } from "node:stream";
3
3
 
4
- import type { MessageInitShape } from "@bufbuild/protobuf";
5
4
  import {
6
5
  createClient,
7
6
  type Client,
@@ -10,11 +9,10 @@ import {
10
9
  import { createGrpcTransport } from "@connectrpc/connect-node";
11
10
 
12
11
  import {
13
- AppendPluginRuntimeLogsRequestSchema,
14
- type AppendPluginRuntimeLogsResponse,
15
12
  PluginRuntimeLogHost as PluginRuntimeLogHostService,
16
- PluginRuntimeLogStream,
13
+ PluginRuntimeLogStream as ProtoPluginRuntimeLogStream,
17
14
  } from "./internal/gen/v1/pluginruntime_pb.ts";
15
+ import { timestampFromDate } from "./protocol.ts";
18
16
 
19
17
  /** Environment variable containing the runtime-log host-service target. */
20
18
  export const ENV_RUNTIME_LOG_HOST_SOCKET = "GESTALT_RUNTIME_LOG_SOCKET";
@@ -28,16 +26,8 @@ const RUNTIME_LOG_RELAY_TOKEN_HEADER = "x-gestalt-host-service-relay-token";
28
26
 
29
27
  /** Named runtime log streams accepted by the authored SDK. */
30
28
  export type RuntimeLogStreamName = "stdout" | "stderr" | "runtime";
31
- /** Runtime log stream input, either a named stream or generated enum value. */
32
- export type RuntimeLogStreamInput =
33
- | RuntimeLogStreamName
34
- | PluginRuntimeLogStream;
35
- /** Shape accepted by `RuntimeLogHost.appendLogs`. */
36
- export type RuntimeLogAppendLogsInput = MessageInitShape<
37
- typeof AppendPluginRuntimeLogsRequestSchema
38
- >;
39
- /** Response message returned after appending runtime logs. */
40
- export type RuntimeLogAppendResponseMessage = AppendPluginRuntimeLogsResponse;
29
+ /** Runtime log stream input accepted by authored APIs. */
30
+ export type RuntimeLogStreamInput = RuntimeLogStreamName;
41
31
 
42
32
  /** One runtime log entry to append through `RuntimeLogHost.append`. */
43
33
  export interface RuntimeLogAppendInput {
@@ -53,6 +43,20 @@ export interface RuntimeLogAppendInput {
53
43
  sourceSeq?: number | bigint;
54
44
  }
55
45
 
46
+ /** Batch of runtime log entries to append through `RuntimeLogHost.appendLogs`. */
47
+ export interface RuntimeLogAppendLogsInput {
48
+ /** Runtime session id. Defaults to `GESTALT_RUNTIME_SESSION_ID`. */
49
+ sessionId?: string | undefined;
50
+ /** Log entries to append. */
51
+ logs: readonly RuntimeLogAppendInput[];
52
+ }
53
+
54
+ /** Response returned after appending runtime logs. */
55
+ export interface RuntimeLogAppendResponse {
56
+ /** Last source sequence accepted by the host. */
57
+ lastSeq: bigint;
58
+ }
59
+
56
60
  /** Options for the `Writable` returned by `RuntimeLogHost.writer`. */
57
61
  export interface RuntimeLogWriterOptions {
58
62
  /** Runtime session id. Defaults to `GESTALT_RUNTIME_SESSION_ID`. */
@@ -66,8 +70,8 @@ export interface RuntimeLogWriterOptions {
66
70
  /**
67
71
  * Client for appending plugin-runtime logs to the host.
68
72
  *
69
- * Use `append` for a single entry, `appendLogs` for a protocol-shaped batch, or
70
- * `writer` to bridge Node streams into the runtime log host.
73
+ * Use `append` for a single entry, `appendLogs` for a native batch, or `writer`
74
+ * to bridge Node streams into the runtime log host.
71
75
  */
72
76
  export class RuntimeLogHost {
73
77
  private readonly client: Client<typeof PluginRuntimeLogHostService>;
@@ -102,31 +106,23 @@ export class RuntimeLogHost {
102
106
 
103
107
  async appendLogs(
104
108
  request: RuntimeLogAppendLogsInput,
105
- ): Promise<RuntimeLogAppendResponseMessage> {
106
- return await this.client.appendLogs(request);
109
+ ): Promise<RuntimeLogAppendResponse> {
110
+ const sessionId = runtimeLogBatchSessionId(request);
111
+ return runtimeLogAppendResponseFromProto(
112
+ await this.client.appendLogs({
113
+ sessionId,
114
+ logs: request.logs.map((log) => this.runtimeLogEntryToProto(log)),
115
+ }),
116
+ );
107
117
  }
108
118
 
109
119
  /** Appends one runtime log entry. */
110
120
  async append(
111
121
  input: RuntimeLogAppendInput,
112
- ): Promise<RuntimeLogAppendResponseMessage> {
113
- const sourceSeq =
114
- input.sourceSeq === undefined
115
- ? (this.sourceSeq += 1n)
116
- : BigInt(input.sourceSeq);
117
- if (sourceSeq > this.sourceSeq) {
118
- this.sourceSeq = sourceSeq;
119
- }
122
+ ): Promise<RuntimeLogAppendResponse> {
120
123
  return await this.appendLogs({
121
- sessionId: runtimeSessionId(input.sessionId),
122
- logs: [
123
- {
124
- stream: runtimeLogStream(input.stream ?? "runtime"),
125
- message: runtimeLogMessage(input.message),
126
- observedAt: toProtoTimestamp(input.observedAt ?? new Date()),
127
- sourceSeq,
128
- },
129
- ],
124
+ sessionId: input.sessionId,
125
+ logs: [input],
130
126
  });
131
127
  }
132
128
 
@@ -171,6 +167,22 @@ export class RuntimeLogHost {
171
167
  },
172
168
  });
173
169
  }
170
+
171
+ private runtimeLogEntryToProto(input: RuntimeLogAppendInput) {
172
+ const sourceSeq =
173
+ input.sourceSeq === undefined
174
+ ? (this.sourceSeq += 1n)
175
+ : BigInt(input.sourceSeq);
176
+ if (sourceSeq > this.sourceSeq) {
177
+ this.sourceSeq = sourceSeq;
178
+ }
179
+ return {
180
+ stream: runtimeLogStream(input.stream ?? "runtime"),
181
+ message: runtimeLogMessage(input.message),
182
+ observedAt: timestampFromDate(input.observedAt ?? new Date()),
183
+ sourceSeq,
184
+ };
185
+ }
174
186
  }
175
187
 
176
188
  function runtimeSessionId(sessionId?: string): string {
@@ -181,6 +193,27 @@ function runtimeSessionId(sessionId?: string): string {
181
193
  return value;
182
194
  }
183
195
 
196
+ function runtimeLogBatchSessionId(request: RuntimeLogAppendLogsInput): string {
197
+ const explicitSessionIds = new Set<string>();
198
+ addRuntimeLogSessionId(explicitSessionIds, request.sessionId);
199
+ for (const log of request.logs) {
200
+ addRuntimeLogSessionId(explicitSessionIds, log.sessionId);
201
+ }
202
+ if (explicitSessionIds.size > 1) {
203
+ throw new Error("runtime log host: appendLogs entries must use one session id");
204
+ }
205
+ return runtimeSessionId(
206
+ request.sessionId ?? request.logs.find((log) => log.sessionId)?.sessionId,
207
+ );
208
+ }
209
+
210
+ function addRuntimeLogSessionId(values: Set<string>, sessionId?: string): void {
211
+ const value = sessionId?.trim();
212
+ if (value) {
213
+ values.add(value);
214
+ }
215
+ }
216
+
184
217
  function runtimeLogTransportOptions(rawTarget: string): {
185
218
  baseUrl: string;
186
219
  nodeOptions?: { path: string };
@@ -232,17 +265,22 @@ function runtimeLogRelayTokenInterceptor(token: string): Interceptor {
232
265
  };
233
266
  }
234
267
 
235
- function runtimeLogStream(stream: RuntimeLogStreamInput): PluginRuntimeLogStream {
236
- if (typeof stream === "number") {
237
- return stream;
238
- }
268
+ function runtimeLogAppendResponseFromProto(
269
+ response: { lastSeq: bigint },
270
+ ): RuntimeLogAppendResponse {
271
+ return { lastSeq: response.lastSeq };
272
+ }
273
+
274
+ function runtimeLogStream(
275
+ stream: RuntimeLogStreamInput,
276
+ ): ProtoPluginRuntimeLogStream {
239
277
  switch (stream.trim().toLowerCase()) {
240
278
  case "stdout":
241
- return PluginRuntimeLogStream.STDOUT;
279
+ return ProtoPluginRuntimeLogStream.STDOUT;
242
280
  case "stderr":
243
- return PluginRuntimeLogStream.STDERR;
281
+ return ProtoPluginRuntimeLogStream.STDERR;
244
282
  case "runtime":
245
- return PluginRuntimeLogStream.RUNTIME;
283
+ return ProtoPluginRuntimeLogStream.RUNTIME;
246
284
  default:
247
285
  throw new Error(`unsupported runtime log stream ${JSON.stringify(stream)}`);
248
286
  }
@@ -255,16 +293,6 @@ function runtimeLogMessage(message: string | Uint8Array): string {
255
293
  return Buffer.from(message).toString("utf8");
256
294
  }
257
295
 
258
- function toProtoTimestamp(value: Date): { seconds: bigint; nanos: number } {
259
- const millis = value.getTime();
260
- const seconds = Math.floor(millis / 1000);
261
- const nanos = Math.trunc((millis - (seconds * 1000)) * 1_000_000);
262
- return {
263
- seconds: BigInt(seconds),
264
- nanos,
265
- };
266
- }
267
-
268
296
  function toError(error: unknown): Error {
269
297
  return error instanceof Error ? error : new Error(String(error));
270
298
  }
package/src/runtime.ts CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  type CompleteLoginRequest as AuthCompleteLoginRequest,
26
26
  type ValidateExternalTokenRequest,
27
27
  } from "./internal/gen/v1/authentication_pb.ts";
28
+ import { AuthorizationProvider as AuthorizationProviderService } from "./internal/gen/v1/authorization_pb.ts";
28
29
  import {
29
30
  Cache as CacheService,
30
31
  CacheDeleteManyResponseSchema,
@@ -45,6 +46,7 @@ import {
45
46
  CatalogSchema as ProtoCatalogSchema,
46
47
  ConnectionMode as ProviderConnectionMode,
47
48
  GetSessionCatalogResponseSchema,
49
+ OperationAnnotationsSchema as ProtoOperationAnnotationsSchema,
48
50
  PostConnectResponseSchema,
49
51
  ResolveHTTPSubjectResponseSchema,
50
52
  OperationResultSchema,
@@ -84,9 +86,15 @@ import {
84
86
  isAuthenticationProvider,
85
87
  type AuthenticatedUser,
86
88
  } from "./auth.ts";
89
+ import {
90
+ AuthorizationProvider,
91
+ createAuthorizationProviderService,
92
+ isAuthorizationProvider,
93
+ } from "./authorization.ts";
87
94
  import { CacheProvider, isCacheProvider } from "./cache.ts";
88
95
  import { SecretsProvider, isSecretsProvider } from "./secrets.ts";
89
96
  import { catalogToYaml, type Catalog } from "./catalog.ts";
97
+ import { valueFromJson, type JsonInput } from "./protocol.ts";
90
98
  import {
91
99
  HTTPSubjectResolutionError,
92
100
  type HTTPSubjectRequest,
@@ -145,6 +153,7 @@ export const CURRENT_PROTOCOL_VERSION = 3;
145
153
  */
146
154
  export const USAGE = "usage: bun run runtime.ts ROOT PROVIDER_TARGET";
147
155
  export { createAgentProviderService } from "./agent.ts";
156
+ export { createAuthorizationProviderService } from "./authorization.ts";
148
157
  export { createPluginRuntimeProviderService } from "./pluginruntime.ts";
149
158
  export { createWorkflowProviderService } from "./workflow.ts";
150
159
 
@@ -162,6 +171,7 @@ export type RuntimeArgs = {
162
171
  export type LoadedProvider =
163
172
  | PluginProvider
164
173
  | AuthenticationProvider
174
+ | AuthorizationProvider
165
175
  | CacheProvider
166
176
  | SecretsProvider
167
177
  | S3Provider
@@ -199,6 +209,18 @@ const PROVIDER_RUNTIME_ENTRIES: Partial<
199
209
  );
200
210
  },
201
211
  },
212
+ authorization: {
213
+ isProvider: isAuthorizationProvider as (
214
+ value: unknown,
215
+ ) => value is LoadedProvider,
216
+ protoKind: ProtoProviderKind.AUTHORIZATION,
217
+ registerService(router, provider) {
218
+ router.service(
219
+ AuthorizationProviderService,
220
+ createAuthorizationProviderService(provider as AuthorizationProvider),
221
+ );
222
+ },
223
+ },
202
224
  cache: {
203
225
  isProvider: isCacheProvider as (value: unknown) => value is LoadedProvider,
204
226
  protoKind: ProtoProviderKind.CACHE,
@@ -596,6 +618,7 @@ export function createProviderService(
596
618
  kind: subject.kind,
597
619
  displayName: subject.displayName,
598
620
  authSource: subject.authSource,
621
+ email: subject.email ?? "",
599
622
  },
600
623
  }
601
624
  : {});
@@ -822,6 +845,9 @@ function providerRequest(
822
845
  idempotencyKey = "",
823
846
  ): Request {
824
847
  const subject = requestContext?.subject;
848
+ const agentSubject = requestContext?.agentSubject;
849
+ const externalIdentity = requestContext?.externalIdentity;
850
+ const agentExternalIdentity = requestContext?.agentExternalIdentity;
825
851
  const credential = requestContext?.credential;
826
852
  const access = requestContext?.access;
827
853
  const host = requestContext?.host;
@@ -835,6 +861,22 @@ function providerRequest(
835
861
  kind: subject?.kind ?? "",
836
862
  displayName: subject?.displayName ?? "",
837
863
  authSource: subject?.authSource ?? "",
864
+ email: subject?.email ?? "",
865
+ },
866
+ agentSubject: {
867
+ id: agentSubject?.id ?? "",
868
+ kind: agentSubject?.kind ?? "",
869
+ displayName: agentSubject?.displayName ?? "",
870
+ authSource: agentSubject?.authSource ?? "",
871
+ email: agentSubject?.email ?? "",
872
+ },
873
+ externalIdentity: {
874
+ type: externalIdentity?.type ?? "",
875
+ id: externalIdentity?.id ?? "",
876
+ },
877
+ agentExternalIdentity: {
878
+ type: agentExternalIdentity?.type ?? "",
879
+ id: agentExternalIdentity?.id ?? "",
838
880
  },
839
881
  credential: {
840
882
  mode: credential?.mode ?? "",
@@ -982,8 +1024,20 @@ function catalogToProto(catalog: Catalog | Record<string, unknown>) {
982
1024
  method: op.method,
983
1025
  title: op.title ?? "",
984
1026
  description: op.description ?? "",
1027
+ inputSchema: catalogSchemaToWire(op.inputSchema),
1028
+ outputSchema: catalogSchemaToWire(op.outputSchema),
1029
+ annotations: op.annotations
1030
+ ? create(ProtoOperationAnnotationsSchema, {
1031
+ readOnlyHint: op.annotations.readOnlyHint,
1032
+ idempotentHint: op.annotations.idempotentHint,
1033
+ destructiveHint: op.annotations.destructiveHint,
1034
+ openWorldHint: op.annotations.openWorldHint,
1035
+ })
1036
+ : undefined,
1037
+ requiredScopes: op.requiredScopes ?? [],
985
1038
  tags: op.tags ?? [],
986
1039
  readOnly: op.readOnly ?? false,
1040
+ transport: op.transport ?? "",
987
1041
  allowedRoles: op.allowedRoles ?? [],
988
1042
  parameters: (op.parameters ?? []).map((p) =>
989
1043
  create(ProtoCatalogParameterSchema, {
@@ -991,6 +1045,9 @@ function catalogToProto(catalog: Catalog | Record<string, unknown>) {
991
1045
  type: p.type,
992
1046
  description: p.description ?? "",
993
1047
  required: p.required ?? false,
1048
+ default: p.default !== undefined
1049
+ ? valueFromJson(p.default as JsonInput)
1050
+ : undefined,
994
1051
  }),
995
1052
  ),
996
1053
  });
@@ -1002,6 +1059,16 @@ function catalogToProto(catalog: Catalog | Record<string, unknown>) {
1002
1059
  });
1003
1060
  }
1004
1061
 
1062
+ function catalogSchemaToWire(schema: unknown): string {
1063
+ if (schema === undefined || schema === null) {
1064
+ return "";
1065
+ }
1066
+ if (typeof schema === "string") {
1067
+ return schema;
1068
+ }
1069
+ return JSON.stringify(schema);
1070
+ }
1071
+
1005
1072
  function authenticatedUserToProto(user: AuthenticatedUser) {
1006
1073
  return create(AuthenticatedUserSchema, {
1007
1074
  subject: user.subject,