@smithers-orchestrator/gateway-client 0.18.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 William Cory
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@smithers-orchestrator/gateway-client",
3
+ "version": "0.18.0",
4
+ "description": "Browser-first client SDK for the Smithers Gateway RPC and event stream APIs",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./src/index.ts",
10
+ "import": "./src/index.ts",
11
+ "default": "./src/index.ts"
12
+ },
13
+ "./*": {
14
+ "types": "./src/*.ts",
15
+ "import": "./src/*.ts",
16
+ "default": "./src/*.ts"
17
+ }
18
+ },
19
+ "files": [
20
+ "src/"
21
+ ],
22
+ "dependencies": {
23
+ "@smithers-orchestrator/gateway": "0.18.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/bun": "latest",
27
+ "typescript": "~5.9.3"
28
+ },
29
+ "scripts": {
30
+ "build": "node ../../node_modules/tsup/dist/cli-default.js --dts-only",
31
+ "typecheck": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json --noEmit",
32
+ "test": "bun test tests"
33
+ }
34
+ }
@@ -0,0 +1,8 @@
1
+ export type GatewayEventFrame<Payload = unknown> = {
2
+ type: "event";
3
+ event: string;
4
+ payload?: Payload;
5
+ seq: number;
6
+ stateVersion: number;
7
+ apiVersion?: "v1";
8
+ };
@@ -0,0 +1,6 @@
1
+ export type GatewayRequestFrame = {
2
+ type: "req";
3
+ id: string;
4
+ method: string;
5
+ params?: unknown;
6
+ };
@@ -0,0 +1,22 @@
1
+ export type GatewayResponseFrame<Payload = unknown> =
2
+ | {
3
+ type: "res";
4
+ id: string;
5
+ ok: true;
6
+ apiVersion?: "v1";
7
+ payload: Payload;
8
+ }
9
+ | {
10
+ type: "res";
11
+ id: string;
12
+ ok: false;
13
+ apiVersion?: "v1";
14
+ error: {
15
+ version?: "v1";
16
+ code: string;
17
+ message: string;
18
+ requiredScope?: string;
19
+ refresh?: string;
20
+ details?: unknown;
21
+ };
22
+ };
@@ -0,0 +1,27 @@
1
+ export class GatewayRpcError extends Error {
2
+ readonly code: string;
3
+ readonly method: string;
4
+ readonly status?: number;
5
+ readonly requiredScope?: string;
6
+ readonly refresh?: string;
7
+ readonly details?: unknown;
8
+
9
+ constructor(input: {
10
+ method: string;
11
+ code: string;
12
+ message: string;
13
+ status?: number;
14
+ requiredScope?: string;
15
+ refresh?: string;
16
+ details?: unknown;
17
+ }) {
18
+ super(input.message);
19
+ this.name = "GatewayRpcError";
20
+ this.method = input.method;
21
+ this.code = input.code;
22
+ this.status = input.status;
23
+ this.requiredScope = input.requiredScope;
24
+ this.refresh = input.refresh;
25
+ this.details = input.details;
26
+ }
27
+ }
@@ -0,0 +1,77 @@
1
+ import type {
2
+ CancelRunRequest,
3
+ CancelRunResponse,
4
+ CronCreateRequest,
5
+ CronDeleteRequest,
6
+ CronListRequest,
7
+ CronRunRequest,
8
+ GatewayRpcMethod,
9
+ HijackRunRequest,
10
+ HijackRunResponse,
11
+ LaunchRunRequest,
12
+ LaunchRunResponse,
13
+ ListApprovalsRequest,
14
+ ListApprovalsResponse,
15
+ ListRunsRequest,
16
+ ListWorkflowsRequest,
17
+ ListWorkflowsResponse,
18
+ NodeRequest,
19
+ RewindRunRequest,
20
+ ResumeRunRequest,
21
+ ResumeRunResponse,
22
+ StreamDevToolsRequest,
23
+ StreamRunEventsRequest,
24
+ StreamRunEventsResponse,
25
+ SubmitApprovalRequest,
26
+ SubmitApprovalResponse,
27
+ SubmitSignalRequest,
28
+ GetRunRequest,
29
+ } from "@smithers-orchestrator/gateway/rpc";
30
+
31
+ export type GatewayRpcRequestMap = {
32
+ launchRun: LaunchRunRequest;
33
+ resumeRun: ResumeRunRequest;
34
+ cancelRun: CancelRunRequest;
35
+ hijackRun: HijackRunRequest;
36
+ rewindRun: RewindRunRequest;
37
+ submitApproval: SubmitApprovalRequest;
38
+ submitSignal: SubmitSignalRequest;
39
+ getRun: GetRunRequest;
40
+ listRuns: ListRunsRequest;
41
+ listWorkflows: ListWorkflowsRequest;
42
+ listApprovals: ListApprovalsRequest;
43
+ streamRunEvents: StreamRunEventsRequest;
44
+ streamDevTools: StreamDevToolsRequest;
45
+ getNodeOutput: NodeRequest;
46
+ getNodeDiff: NodeRequest;
47
+ cronList: CronListRequest;
48
+ cronCreate: CronCreateRequest;
49
+ cronDelete: CronDeleteRequest;
50
+ cronRun: CronRunRequest;
51
+ };
52
+
53
+ export type GatewayRpcResponseMap = {
54
+ launchRun: LaunchRunResponse;
55
+ resumeRun: ResumeRunResponse;
56
+ cancelRun: CancelRunResponse;
57
+ hijackRun: HijackRunResponse;
58
+ rewindRun: Record<string, unknown>;
59
+ submitApproval: SubmitApprovalResponse;
60
+ submitSignal: Record<string, unknown>;
61
+ getRun: Record<string, unknown>;
62
+ listRuns: Array<Record<string, unknown>>;
63
+ listWorkflows: ListWorkflowsResponse;
64
+ listApprovals: ListApprovalsResponse;
65
+ streamRunEvents: StreamRunEventsResponse;
66
+ streamDevTools: Record<string, unknown>;
67
+ getNodeOutput: Record<string, unknown>;
68
+ getNodeDiff: Record<string, unknown>;
69
+ cronList: Array<Record<string, unknown>>;
70
+ cronCreate: Record<string, unknown>;
71
+ cronDelete: Record<string, unknown>;
72
+ cronRun: LaunchRunResponse;
73
+ };
74
+
75
+ export type GatewayRpcParams<Method extends GatewayRpcMethod> = GatewayRpcRequestMap[Method];
76
+
77
+ export type GatewayRpcPayload<Method extends GatewayRpcMethod> = GatewayRpcResponseMap[Method];
@@ -0,0 +1,10 @@
1
+ export type GatewayUiBootConfig = {
2
+ apiVersion: "v1";
3
+ kind: "gateway" | "workflow";
4
+ workflowKey: string | null;
5
+ mountPath: string;
6
+ rpcPath: string;
7
+ wsPath: string;
8
+ assetBasePath: string;
9
+ props: Record<string, unknown>;
10
+ };
@@ -0,0 +1,227 @@
1
+ import type { GatewayRpcMethod } from "@smithers-orchestrator/gateway/rpc";
2
+ import { GatewayRpcError } from "./GatewayRpcError.ts";
3
+ import type { GatewayEventFrame } from "./GatewayEventFrame.ts";
4
+ import type { GatewayResponseFrame } from "./GatewayResponseFrame.ts";
5
+ import type { GatewayUiBootConfig } from "./GatewayUiBootConfig.ts";
6
+ import { SmithersGatewayConnection } from "./SmithersGatewayConnection.ts";
7
+ import type { SmithersGatewayClientOptions } from "./SmithersGatewayClientOptions.ts";
8
+ import type { GatewayRpcParams, GatewayRpcPayload } from "./GatewayRpcTypeMap.ts";
9
+
10
+ type StreamRunEventPayload = {
11
+ streamId?: string;
12
+ runId?: string;
13
+ seq?: number;
14
+ event?: string;
15
+ payload?: unknown;
16
+ };
17
+
18
+ declare global {
19
+ var __SMITHERS_GATEWAY_UI__: GatewayUiBootConfig | undefined;
20
+ }
21
+
22
+ function defaultBaseUrl() {
23
+ if (typeof globalThis.location !== "undefined") {
24
+ return globalThis.location.origin;
25
+ }
26
+ return "http://127.0.0.1:7331";
27
+ }
28
+
29
+ function normalizeBaseUrl(baseUrl: string) {
30
+ return baseUrl.replace(/\/+$/, "");
31
+ }
32
+
33
+ function toWebSocketUrl(baseUrl: string, wsPath = "/") {
34
+ const url = new URL(wsPath, baseUrl);
35
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
36
+ return url.toString();
37
+ }
38
+
39
+ function randomId(method: string) {
40
+ const cryptoApi = globalThis.crypto;
41
+ const suffix = typeof cryptoApi?.randomUUID === "function"
42
+ ? cryptoApi.randomUUID()
43
+ : Math.random().toString(36).slice(2);
44
+ return `${method}-${suffix}`;
45
+ }
46
+
47
+ function headersFromOptions(options: SmithersGatewayClientOptions) {
48
+ const headers = new Headers(options.headers);
49
+ headers.set("content-type", "application/json");
50
+ if (options.token) {
51
+ headers.set("authorization", `Bearer ${options.token}`);
52
+ }
53
+ return headers;
54
+ }
55
+
56
+ function rpcError(frame: Extract<GatewayResponseFrame, { ok: false }>, method: string, status?: number) {
57
+ return new GatewayRpcError({
58
+ method,
59
+ status,
60
+ code: frame.error.code,
61
+ message: frame.error.message,
62
+ requiredScope: frame.error.requiredScope,
63
+ refresh: frame.error.refresh,
64
+ details: frame.error.details,
65
+ });
66
+ }
67
+
68
+ export class SmithersGatewayClient {
69
+ readonly baseUrl: string;
70
+ readonly token?: string;
71
+ readonly fetchImpl: typeof fetch;
72
+ readonly WebSocketImpl: typeof WebSocket;
73
+ readonly headers: HeadersInit | undefined;
74
+ readonly client: Required<NonNullable<SmithersGatewayClientOptions["client"]>>;
75
+ readonly boot: GatewayUiBootConfig | undefined;
76
+
77
+ constructor(options: SmithersGatewayClientOptions = {}) {
78
+ this.boot = globalThis.__SMITHERS_GATEWAY_UI__;
79
+ this.baseUrl = normalizeBaseUrl(options.baseUrl ?? defaultBaseUrl());
80
+ this.token = options.token;
81
+ this.headers = options.headers;
82
+ this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
83
+ this.WebSocketImpl = options.WebSocket ?? globalThis.WebSocket;
84
+ this.client = {
85
+ id: options.client?.id ?? "smithers-gateway-client",
86
+ version: options.client?.version ?? "0.17.0",
87
+ platform: options.client?.platform ?? "browser",
88
+ };
89
+ }
90
+
91
+ rpc<Method extends GatewayRpcMethod>(
92
+ method: Method,
93
+ params: GatewayRpcParams<Method>,
94
+ options: { signal?: AbortSignal } = {},
95
+ ): Promise<GatewayRpcPayload<Method>> {
96
+ return this.rpcRaw(method, params, options) as Promise<GatewayRpcPayload<Method>>;
97
+ }
98
+
99
+ async rpcRaw(method: string, params?: unknown, options: { signal?: AbortSignal } = {}) {
100
+ const response = await this.fetchImpl(`${this.baseUrl}/v1/rpc/${method}`, {
101
+ method: "POST",
102
+ headers: headersFromOptions(this),
103
+ body: JSON.stringify(params ?? {}),
104
+ signal: options.signal,
105
+ });
106
+ const frame = (await response.json()) as GatewayResponseFrame;
107
+ if (!response.ok && !("ok" in frame)) {
108
+ throw new GatewayRpcError({
109
+ method,
110
+ status: response.status,
111
+ code: "HTTP_ERROR",
112
+ message: `Gateway HTTP ${response.status}`,
113
+ });
114
+ }
115
+ if (!frame.ok) {
116
+ throw rpcError(frame, method, response.status);
117
+ }
118
+ return frame.payload;
119
+ }
120
+
121
+ async connect(options: { subscribe?: string[]; signal?: AbortSignal } = {}) {
122
+ if (!this.WebSocketImpl) {
123
+ throw new Error("WebSocket is not available in this environment.");
124
+ }
125
+ const ws = new this.WebSocketImpl(toWebSocketUrl(this.baseUrl, this.boot?.wsPath));
126
+ await new Promise<void>((resolve, reject) => {
127
+ const onOpen = () => {
128
+ cleanup();
129
+ resolve();
130
+ };
131
+ const onError = () => {
132
+ cleanup();
133
+ reject(new Error("Gateway WebSocket failed to open."));
134
+ };
135
+ const cleanup = () => {
136
+ ws.removeEventListener("open", onOpen);
137
+ ws.removeEventListener("error", onError);
138
+ };
139
+ ws.addEventListener("open", onOpen);
140
+ ws.addEventListener("error", onError);
141
+ options.signal?.addEventListener("abort", () => {
142
+ cleanup();
143
+ ws.close();
144
+ reject(new Error("Gateway WebSocket open aborted."));
145
+ }, { once: true });
146
+ });
147
+ const connection = new SmithersGatewayConnection(ws);
148
+ await connection.requestRaw("connect", {
149
+ minProtocol: 1,
150
+ maxProtocol: 1,
151
+ client: this.client,
152
+ ...(this.token ? { auth: { token: this.token } } : {}),
153
+ ...(options.subscribe ? { subscribe: options.subscribe } : {}),
154
+ });
155
+ return connection;
156
+ }
157
+
158
+ async *streamRunEvents(
159
+ params: GatewayRpcParams<"streamRunEvents">,
160
+ options: { signal?: AbortSignal } = {},
161
+ ): AsyncGenerator<GatewayEventFrame<StreamRunEventPayload>> {
162
+ const connection = await this.connect({ subscribe: [params.runId], signal: options.signal });
163
+ try {
164
+ const subscribed = await connection.request("streamRunEvents", params);
165
+ for await (const frame of connection.events(options.signal)) {
166
+ if (
167
+ (frame.event === "run.event" ||
168
+ frame.event === "run.gap_resync" ||
169
+ frame.event === "run.heartbeat" ||
170
+ frame.event === "run.error") &&
171
+ typeof frame.payload === "object" &&
172
+ frame.payload !== null &&
173
+ "streamId" in frame.payload &&
174
+ frame.payload.streamId === subscribed.streamId
175
+ ) {
176
+ yield frame as GatewayEventFrame<StreamRunEventPayload>;
177
+ }
178
+ }
179
+ } finally {
180
+ connection.close();
181
+ }
182
+ }
183
+
184
+ launchRun(params: GatewayRpcParams<"launchRun">) {
185
+ return this.rpc("launchRun", params);
186
+ }
187
+
188
+ resumeRun(params: GatewayRpcParams<"resumeRun">) {
189
+ return this.rpc("resumeRun", params);
190
+ }
191
+
192
+ cancelRun(params: GatewayRpcParams<"cancelRun">) {
193
+ return this.rpc("cancelRun", params);
194
+ }
195
+
196
+ submitApproval(params: GatewayRpcParams<"submitApproval">) {
197
+ return this.rpc("submitApproval", params);
198
+ }
199
+
200
+ submitSignal(params: GatewayRpcParams<"submitSignal">) {
201
+ return this.rpc("submitSignal", params);
202
+ }
203
+
204
+ getRun(params: GatewayRpcParams<"getRun">) {
205
+ return this.rpc("getRun", params);
206
+ }
207
+
208
+ listRuns(params: GatewayRpcParams<"listRuns"> = {}) {
209
+ return this.rpc("listRuns", params);
210
+ }
211
+
212
+ listWorkflows(params: GatewayRpcParams<"listWorkflows"> = {}) {
213
+ return this.rpc("listWorkflows", params);
214
+ }
215
+
216
+ listApprovals(params: GatewayRpcParams<"listApprovals"> = {}) {
217
+ return this.rpc("listApprovals", params);
218
+ }
219
+
220
+ getNodeOutput(params: GatewayRpcParams<"getNodeOutput">) {
221
+ return this.rpc("getNodeOutput", params);
222
+ }
223
+
224
+ getNodeDiff(params: GatewayRpcParams<"getNodeDiff">) {
225
+ return this.rpc("getNodeDiff", params);
226
+ }
227
+ }
@@ -0,0 +1,12 @@
1
+ export type SmithersGatewayClientOptions = {
2
+ baseUrl?: string;
3
+ token?: string;
4
+ headers?: HeadersInit;
5
+ fetch?: typeof fetch;
6
+ WebSocket?: typeof WebSocket;
7
+ client?: {
8
+ id?: string;
9
+ version?: string;
10
+ platform?: string;
11
+ };
12
+ };
@@ -0,0 +1,154 @@
1
+ import type { GatewayRpcMethod } from "@smithers-orchestrator/gateway/rpc";
2
+ import { GatewayRpcError } from "./GatewayRpcError.ts";
3
+ import type { GatewayEventFrame } from "./GatewayEventFrame.ts";
4
+ import type { GatewayResponseFrame } from "./GatewayResponseFrame.ts";
5
+ import type { GatewayRpcParams, GatewayRpcPayload } from "./GatewayRpcTypeMap.ts";
6
+
7
+ type PendingRequest = {
8
+ resolve: (payload: unknown) => void;
9
+ reject: (error: Error) => void;
10
+ method: string;
11
+ };
12
+
13
+ type QueuedEvent =
14
+ | { kind: "event"; frame: GatewayEventFrame }
15
+ | { kind: "error"; error: Error }
16
+ | { kind: "close" };
17
+
18
+ function randomId(method: string) {
19
+ const cryptoApi = globalThis.crypto;
20
+ const suffix = typeof cryptoApi?.randomUUID === "function"
21
+ ? cryptoApi.randomUUID()
22
+ : Math.random().toString(36).slice(2);
23
+ return `${method}-${suffix}`;
24
+ }
25
+
26
+ function frameError(frame: Extract<GatewayResponseFrame, { ok: false }>, method: string) {
27
+ return new GatewayRpcError({
28
+ method,
29
+ code: frame.error.code,
30
+ message: frame.error.message,
31
+ requiredScope: frame.error.requiredScope,
32
+ refresh: frame.error.refresh,
33
+ details: frame.error.details,
34
+ });
35
+ }
36
+
37
+ export class SmithersGatewayConnection {
38
+ readonly ws: WebSocket;
39
+ readonly pending = new Map<string, PendingRequest>();
40
+ readonly queue: QueuedEvent[] = [];
41
+ readonly waiters: Array<() => void> = [];
42
+ closed = false;
43
+
44
+ constructor(ws: WebSocket) {
45
+ this.ws = ws;
46
+ ws.addEventListener("message", (message) => {
47
+ this.handleMessage(message.data);
48
+ });
49
+ ws.addEventListener("error", () => {
50
+ this.push({ kind: "error", error: new Error("Gateway WebSocket error") });
51
+ });
52
+ ws.addEventListener("close", () => {
53
+ this.closed = true;
54
+ for (const pending of this.pending.values()) {
55
+ pending.reject(new Error("Gateway WebSocket closed"));
56
+ }
57
+ this.pending.clear();
58
+ this.push({ kind: "close" });
59
+ });
60
+ }
61
+
62
+ request<Method extends GatewayRpcMethod>(
63
+ method: Method,
64
+ params: GatewayRpcParams<Method>,
65
+ ): Promise<GatewayRpcPayload<Method>> {
66
+ const id = randomId(method);
67
+ const frame = { type: "req", id, method, params };
68
+ return new Promise((resolve, reject) => {
69
+ this.pending.set(id, {
70
+ method,
71
+ resolve: (payload) => resolve(payload as GatewayRpcPayload<Method>),
72
+ reject,
73
+ });
74
+ this.ws.send(JSON.stringify(frame));
75
+ });
76
+ }
77
+
78
+ requestRaw(method: string, params?: unknown): Promise<unknown> {
79
+ const id = randomId(method);
80
+ const frame = { type: "req", id, method, params };
81
+ return new Promise((resolve, reject) => {
82
+ this.pending.set(id, { method, resolve, reject });
83
+ this.ws.send(JSON.stringify(frame));
84
+ });
85
+ }
86
+
87
+ async *events(signal?: AbortSignal): AsyncGenerator<GatewayEventFrame> {
88
+ const abort = () => this.close();
89
+ signal?.addEventListener("abort", abort, { once: true });
90
+ try {
91
+ while (!this.closed || this.queue.length > 0) {
92
+ const next = await this.shift();
93
+ if (!next || next.kind === "close") {
94
+ return;
95
+ }
96
+ if (next.kind === "error") {
97
+ throw next.error;
98
+ }
99
+ yield next.frame;
100
+ }
101
+ } finally {
102
+ signal?.removeEventListener("abort", abort);
103
+ }
104
+ }
105
+
106
+ close() {
107
+ if (this.closed) {
108
+ return;
109
+ }
110
+ this.closed = true;
111
+ this.ws.close();
112
+ }
113
+
114
+ private handleMessage(raw: unknown) {
115
+ const text = typeof raw === "string" ? raw : String(raw);
116
+ const frame = JSON.parse(text) as GatewayResponseFrame | GatewayEventFrame;
117
+ if (frame.type === "res") {
118
+ const pending = this.pending.get(frame.id);
119
+ if (!pending) {
120
+ return;
121
+ }
122
+ this.pending.delete(frame.id);
123
+ if (frame.ok) {
124
+ pending.resolve(frame.payload);
125
+ return;
126
+ }
127
+ pending.reject(frameError(frame, pending.method));
128
+ return;
129
+ }
130
+ if (frame.type === "event") {
131
+ this.push({ kind: "event", frame });
132
+ }
133
+ }
134
+
135
+ private push(event: QueuedEvent) {
136
+ this.queue.push(event);
137
+ const waiters = this.waiters.splice(0);
138
+ for (const waiter of waiters) {
139
+ waiter();
140
+ }
141
+ }
142
+
143
+ private async shift(): Promise<QueuedEvent | undefined> {
144
+ while (this.queue.length === 0) {
145
+ if (this.closed) {
146
+ return { kind: "close" };
147
+ }
148
+ await new Promise<void>((resolve) => {
149
+ this.waiters.push(resolve);
150
+ });
151
+ }
152
+ return this.queue.shift();
153
+ }
154
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export { GatewayRpcError } from "./GatewayRpcError.ts";
2
+ export { SmithersGatewayClient } from "./SmithersGatewayClient.ts";
3
+ export { SmithersGatewayConnection } from "./SmithersGatewayConnection.ts";
4
+ export type { GatewayEventFrame } from "./GatewayEventFrame.ts";
5
+ export type { GatewayRequestFrame } from "./GatewayRequestFrame.ts";
6
+ export type { GatewayResponseFrame } from "./GatewayResponseFrame.ts";
7
+ export type { GatewayRpcParams, GatewayRpcPayload, GatewayRpcRequestMap, GatewayRpcResponseMap } from "./GatewayRpcTypeMap.ts";
8
+ export type { GatewayUiBootConfig } from "./GatewayUiBootConfig.ts";
9
+ export type { SmithersGatewayClientOptions } from "./SmithersGatewayClientOptions.ts";