@superblocksteam/sdk 1.4.2 → 1.5.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/.eslintrc.json +3 -0
- package/dist/client.d.ts +5 -4
- package/dist/client.js +140 -44
- package/dist/flag.d.ts +2 -0
- package/dist/flag.js +8 -0
- package/dist/sdk.d.ts +5 -5
- package/dist/socket/handlers.d.ts +105 -0
- package/dist/socket/handlers.js +85 -0
- package/dist/socket/index.d.ts +27 -0
- package/dist/socket/index.js +69 -0
- package/dist/socket/signing.d.ts +13 -0
- package/dist/socket/signing.js +81 -0
- package/dist/socket/socket.d.ts +16 -0
- package/dist/socket/socket.js +157 -0
- package/dist/types/common.d.ts +111 -0
- package/dist/types/common.js +33 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +7 -0
- package/dist/types/plugin.d.ts +2 -0
- package/dist/types/plugin.js +9 -0
- package/dist/types/signing.d.ts +51 -0
- package/dist/types/signing.js +2 -0
- package/dist/types/socket.d.ts +17 -0
- package/dist/types/socket.js +2 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +36 -0
- package/package.json +5 -3
- package/src/client.ts +159 -52
- package/src/flag.ts +5 -0
- package/src/sdk.ts +8 -8
- package/src/socket/handlers.ts +228 -0
- package/src/socket/index.ts +164 -0
- package/src/socket/signing.ts +113 -0
- package/src/socket/socket.ts +253 -0
- package/src/types/common.ts +138 -0
- package/src/types/index.ts +4 -0
- package/src/types/plugin.ts +7 -0
- package/src/types/signing.ts +61 -0
- package/src/types/socket.ts +48 -0
- package/src/utils.ts +45 -0
- package/tsconfig.json +3 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import WebSocket from "isomorphic-ws";
|
|
2
|
+
import {
|
|
3
|
+
ClientMethods,
|
|
4
|
+
createRequestHandlers,
|
|
5
|
+
ServerMethods,
|
|
6
|
+
} from "./handlers";
|
|
7
|
+
import { createISocketClient, ISocket } from "./socket";
|
|
8
|
+
|
|
9
|
+
export type StdISocketRPCClient = ISocketClient<ServerMethods>;
|
|
10
|
+
|
|
11
|
+
export async function connectToISocketRPCServer({
|
|
12
|
+
superblocksBaseUrl,
|
|
13
|
+
agentUrls,
|
|
14
|
+
token,
|
|
15
|
+
}: {
|
|
16
|
+
superblocksBaseUrl: string;
|
|
17
|
+
agentUrls: string[];
|
|
18
|
+
token: string;
|
|
19
|
+
}): Promise<StdISocketRPCClient> {
|
|
20
|
+
const requestHandlers = createRequestHandlers({
|
|
21
|
+
agentUrls,
|
|
22
|
+
token,
|
|
23
|
+
});
|
|
24
|
+
const authorization = `Bearer ${token}`;
|
|
25
|
+
const wsUrl = new URL("api/v1/rpc-ws", superblocksBaseUrl);
|
|
26
|
+
if (wsUrl.protocol === "http:") {
|
|
27
|
+
wsUrl.protocol = "ws:";
|
|
28
|
+
} else if (wsUrl.protocol === "https:") {
|
|
29
|
+
wsUrl.protocol = "wss:";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (wsUrl.host === "localhost:3000") {
|
|
33
|
+
wsUrl.host = "127.0.0.1:8080";
|
|
34
|
+
} else if (wsUrl.hostname === "localhost") {
|
|
35
|
+
wsUrl.hostname = "127.0.0.1";
|
|
36
|
+
}
|
|
37
|
+
return await connectISocket<ServerMethods, ClientMethods, unknown>(
|
|
38
|
+
wsUrl.href,
|
|
39
|
+
authorization,
|
|
40
|
+
requestHandlers
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// a subclass of ISocket that sends an auth token on the first request
|
|
45
|
+
// this is useful for client-side sockets that need to authenticate
|
|
46
|
+
// TODO(george): if we start using this for long-lived connections, we should add a way to refresh the token
|
|
47
|
+
class ISocketWithClientAuth<
|
|
48
|
+
ImplementedMethods,
|
|
49
|
+
CallableMethods,
|
|
50
|
+
RequestContext = void
|
|
51
|
+
> extends ISocket<ImplementedMethods, CallableMethods, RequestContext> {
|
|
52
|
+
private readonly authorization?: string;
|
|
53
|
+
private hasSentAuth = false;
|
|
54
|
+
|
|
55
|
+
constructor(
|
|
56
|
+
ws: WebSocket,
|
|
57
|
+
authorization: string | undefined,
|
|
58
|
+
requestHandlers: MethodHandlers<
|
|
59
|
+
ImplementedMethods,
|
|
60
|
+
CallableMethods,
|
|
61
|
+
RequestContext
|
|
62
|
+
>
|
|
63
|
+
) {
|
|
64
|
+
super(ws, requestHandlers);
|
|
65
|
+
this.authorization = authorization;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// override `request` from the base class to send `authorization` when appropriate
|
|
69
|
+
async request<Params, Result>(
|
|
70
|
+
method: string,
|
|
71
|
+
params: Params
|
|
72
|
+
): Promise<Result> {
|
|
73
|
+
// only send `authorization` on the first request
|
|
74
|
+
const authorization = this.hasSentAuth ? undefined : this.authorization;
|
|
75
|
+
const result = await super.request<Params, Result>(
|
|
76
|
+
method,
|
|
77
|
+
params,
|
|
78
|
+
authorization
|
|
79
|
+
);
|
|
80
|
+
this.hasSentAuth = true;
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function connectISocket<
|
|
86
|
+
CallableMethods,
|
|
87
|
+
ImplementedMethods,
|
|
88
|
+
RequestContext = never
|
|
89
|
+
>(
|
|
90
|
+
wsUrl: string,
|
|
91
|
+
authorization: string | undefined,
|
|
92
|
+
requestHandlers: MethodHandlers<
|
|
93
|
+
ImplementedMethods,
|
|
94
|
+
CallableMethods,
|
|
95
|
+
RequestContext
|
|
96
|
+
>
|
|
97
|
+
): Promise<ISocketClient<CallableMethods>> {
|
|
98
|
+
const ws = await connectWebSocket(wsUrl);
|
|
99
|
+
const isocket = new ISocketWithClientAuth(ws, authorization, requestHandlers);
|
|
100
|
+
return createISocketClient(isocket);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function connectWebSocket(wsUrl: string): Promise<WebSocket> {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const ws = new WebSocket(wsUrl);
|
|
106
|
+
|
|
107
|
+
ws.addEventListener("open", () => {
|
|
108
|
+
// Resolve the promise with the WebSocket instance when the connection is open
|
|
109
|
+
resolve(ws);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
ws.addEventListener("error", (error: Error) => {
|
|
115
|
+
// Reject the promise if there's an error
|
|
116
|
+
reject(error);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type MethodHandler<Params, Result, PeerMethods, RequestContext> = (
|
|
122
|
+
params: Params,
|
|
123
|
+
peer: ISocketClient<PeerMethods>,
|
|
124
|
+
ctx: RequestContext
|
|
125
|
+
) => Promise<Result>;
|
|
126
|
+
|
|
127
|
+
type MiddlewareHandler<Params, PeerMethods, RequestContext> = (
|
|
128
|
+
params: Params,
|
|
129
|
+
peerAuthorization: string | undefined,
|
|
130
|
+
peer: ISocketClient<PeerMethods>,
|
|
131
|
+
ctx: RequestContext
|
|
132
|
+
) => Promise<void>;
|
|
133
|
+
|
|
134
|
+
type MethodHandlers<Methods, PeerMethods, RequestContext> = {
|
|
135
|
+
[Key in keyof Methods]: Methods[Key] extends (
|
|
136
|
+
params: infer Params
|
|
137
|
+
) => Promise<infer Result>
|
|
138
|
+
? [
|
|
139
|
+
...middlewareHandlers: MiddlewareHandler<
|
|
140
|
+
Params,
|
|
141
|
+
PeerMethods,
|
|
142
|
+
RequestContext
|
|
143
|
+
>[],
|
|
144
|
+
handler: MethodHandler<Params, Result, PeerMethods, RequestContext>
|
|
145
|
+
]
|
|
146
|
+
: Methods[Key] extends Record<string, unknown>
|
|
147
|
+
? MethodHandlers<Methods[Key], PeerMethods, RequestContext>
|
|
148
|
+
: never;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
type ISocketClientMethodCall<Methods> = {
|
|
152
|
+
[Key in keyof Methods]: Methods[Key] extends (
|
|
153
|
+
params: infer P
|
|
154
|
+
) => Promise<infer R>
|
|
155
|
+
? (params: P) => Promise<R>
|
|
156
|
+
: Methods[Key] extends Record<string, unknown>
|
|
157
|
+
? ISocketClientMethodCall<Methods[Key]>
|
|
158
|
+
: never;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
type ISocketClient<Methods> = {
|
|
162
|
+
close: () => void;
|
|
163
|
+
call: ISocketClientMethodCall<Methods>;
|
|
164
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import axios, { AxiosRequestConfig, Method } from "axios";
|
|
2
|
+
import {
|
|
3
|
+
ApiResource,
|
|
4
|
+
GenericResource,
|
|
5
|
+
Signature,
|
|
6
|
+
SignatureResponse,
|
|
7
|
+
} from "../types";
|
|
8
|
+
import { getSanitizedApi } from "../utils";
|
|
9
|
+
|
|
10
|
+
export async function signResource({
|
|
11
|
+
token,
|
|
12
|
+
branchName,
|
|
13
|
+
resource,
|
|
14
|
+
agentUrls,
|
|
15
|
+
}: {
|
|
16
|
+
token: string;
|
|
17
|
+
branchName: string;
|
|
18
|
+
resource: ApiResource | GenericResource;
|
|
19
|
+
agentUrls: string[];
|
|
20
|
+
}): Promise<Signature> {
|
|
21
|
+
const requestResource: Record<string, any> = {
|
|
22
|
+
branchName: branchName ?? "main",
|
|
23
|
+
};
|
|
24
|
+
if ((resource as ApiResource).api) {
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
26
|
+
requestResource.api = getSanitizedApi((resource as ApiResource).api);
|
|
27
|
+
} else {
|
|
28
|
+
requestResource.literal = (resource as GenericResource).literal;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const resp = await callAgentFallBack<SignatureResponse>({
|
|
33
|
+
baseUrls: agentUrls,
|
|
34
|
+
path: "v1/signature/sign",
|
|
35
|
+
method: "post",
|
|
36
|
+
token: token,
|
|
37
|
+
data: { resource: requestResource },
|
|
38
|
+
});
|
|
39
|
+
return resp.signature;
|
|
40
|
+
} catch (e) {
|
|
41
|
+
throw new Error("No agents available to sign the resource");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function verifyResources({
|
|
46
|
+
agentUrls,
|
|
47
|
+
token,
|
|
48
|
+
branchName,
|
|
49
|
+
resources,
|
|
50
|
+
}: {
|
|
51
|
+
resources: Array<GenericResource | ApiResource>;
|
|
52
|
+
token: string;
|
|
53
|
+
branchName: string;
|
|
54
|
+
agentUrls: string[];
|
|
55
|
+
}): Promise<void> {
|
|
56
|
+
try {
|
|
57
|
+
await callAgentFallBack<{ keyId: string }>({
|
|
58
|
+
baseUrls: agentUrls,
|
|
59
|
+
path: "v1/signature/verify",
|
|
60
|
+
method: "post",
|
|
61
|
+
token: token,
|
|
62
|
+
data: {
|
|
63
|
+
resources: resources.map((res) => {
|
|
64
|
+
if ((res as ApiResource).api) {
|
|
65
|
+
return {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
67
|
+
api: getSanitizedApi((res as ApiResource).api),
|
|
68
|
+
branchName: branchName ?? "main",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
...res,
|
|
73
|
+
branchName: branchName ?? "main",
|
|
74
|
+
};
|
|
75
|
+
}),
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
} catch (e) {
|
|
79
|
+
throw new Error("No agents available to verify the resource");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function callAgentFallBack<T>({
|
|
84
|
+
baseUrls,
|
|
85
|
+
path,
|
|
86
|
+
method,
|
|
87
|
+
token,
|
|
88
|
+
data,
|
|
89
|
+
}: {
|
|
90
|
+
baseUrls: string[];
|
|
91
|
+
path: string;
|
|
92
|
+
method: Method;
|
|
93
|
+
token: string;
|
|
94
|
+
data: any;
|
|
95
|
+
}): Promise<T> {
|
|
96
|
+
for (const baseUrl of baseUrls) {
|
|
97
|
+
try {
|
|
98
|
+
const url = new URL(path, baseUrl);
|
|
99
|
+
const config: AxiosRequestConfig = {
|
|
100
|
+
url: url.toString(),
|
|
101
|
+
method: method,
|
|
102
|
+
headers: {
|
|
103
|
+
Authorization: "Bearer " + token,
|
|
104
|
+
},
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
106
|
+
data: data,
|
|
107
|
+
};
|
|
108
|
+
const resp = await axios<T>(config);
|
|
109
|
+
return resp.data;
|
|
110
|
+
} catch (e) {}
|
|
111
|
+
}
|
|
112
|
+
throw new Error("Failed to request ");
|
|
113
|
+
}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import WebSocket from "isomorphic-ws";
|
|
2
|
+
import {
|
|
3
|
+
ISocketClient,
|
|
4
|
+
MethodHandler,
|
|
5
|
+
MethodHandlers,
|
|
6
|
+
MiddlewareHandler,
|
|
7
|
+
} from "../types";
|
|
8
|
+
|
|
9
|
+
interface SocketRequest<Payload = unknown> {
|
|
10
|
+
method: string;
|
|
11
|
+
payload: Payload;
|
|
12
|
+
id: number;
|
|
13
|
+
setAuthorization?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface SocketResponse<Payload = unknown> {
|
|
17
|
+
id: number;
|
|
18
|
+
payload: Payload;
|
|
19
|
+
error: SocketError | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface SocketMessage<RequestPayload = unknown, ResponsePayload = unknown> {
|
|
23
|
+
request?: SocketRequest<RequestPayload>;
|
|
24
|
+
response?: SocketResponse<ResponsePayload>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface SocketError {
|
|
28
|
+
message: string;
|
|
29
|
+
code: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class ISocket<ImplementedMethods, CallableMethods, RequestContext> {
|
|
33
|
+
private readonly ws: WebSocket;
|
|
34
|
+
private readonly requestHandlers: MethodHandlers<
|
|
35
|
+
ImplementedMethods,
|
|
36
|
+
CallableMethods,
|
|
37
|
+
RequestContext
|
|
38
|
+
>;
|
|
39
|
+
private readonly responseHandler: {
|
|
40
|
+
[requestId: number]: {
|
|
41
|
+
resolve: (data: unknown) => void;
|
|
42
|
+
reject: (error: SocketError) => void;
|
|
43
|
+
};
|
|
44
|
+
} = {};
|
|
45
|
+
private peerAuthorization?: string;
|
|
46
|
+
private nxtRequestId: number;
|
|
47
|
+
|
|
48
|
+
constructor(
|
|
49
|
+
ws: WebSocket,
|
|
50
|
+
requestHandlers: MethodHandlers<
|
|
51
|
+
ImplementedMethods,
|
|
52
|
+
CallableMethods,
|
|
53
|
+
RequestContext
|
|
54
|
+
>
|
|
55
|
+
) {
|
|
56
|
+
this.ws = ws;
|
|
57
|
+
this.requestHandlers = requestHandlers;
|
|
58
|
+
this.nxtRequestId = 0;
|
|
59
|
+
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
this.ws.addEventListener("message", async (event: MessageEvent) => {
|
|
63
|
+
const eventData: SocketMessage = JSON.parse(event.data.toString());
|
|
64
|
+
if (eventData.request) {
|
|
65
|
+
// Split the method string into parts
|
|
66
|
+
const parts = eventData.request.method.split(".");
|
|
67
|
+
let handlers = this.requestHandlers;
|
|
68
|
+
for (const part of parts) {
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
handlers = handlers[part];
|
|
71
|
+
if (!handlers) {
|
|
72
|
+
return await this.respondError(eventData.request.id, {
|
|
73
|
+
code: 2,
|
|
74
|
+
message: `unknown method ${eventData.request.method}`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!Array.isArray(handlers)) {
|
|
80
|
+
return await this.respondError(eventData.request.id, {
|
|
81
|
+
code: 2,
|
|
82
|
+
message: "unknown method",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (eventData.request.setAuthorization) {
|
|
86
|
+
this.peerAuthorization = eventData.request.setAuthorization;
|
|
87
|
+
}
|
|
88
|
+
const middlewareHandlers = handlers.slice(0, -1) as MiddlewareHandler<
|
|
89
|
+
unknown,
|
|
90
|
+
CallableMethods,
|
|
91
|
+
RequestContext
|
|
92
|
+
>[];
|
|
93
|
+
const handler = handlers[handlers.length - 1] as MethodHandler<
|
|
94
|
+
unknown,
|
|
95
|
+
unknown,
|
|
96
|
+
CallableMethods,
|
|
97
|
+
RequestContext
|
|
98
|
+
>;
|
|
99
|
+
const reqCtx = {} as RequestContext;
|
|
100
|
+
let response: unknown;
|
|
101
|
+
// TODO(george): maybe we should not create a new client for each request
|
|
102
|
+
const client = createISocketClient(this);
|
|
103
|
+
try {
|
|
104
|
+
for (const middlewareHandler of middlewareHandlers) {
|
|
105
|
+
await middlewareHandler(
|
|
106
|
+
eventData.request.payload,
|
|
107
|
+
this.peerAuthorization,
|
|
108
|
+
client,
|
|
109
|
+
reqCtx
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
response = await handler(eventData.request.payload, client, reqCtx);
|
|
113
|
+
} catch (error: any) {
|
|
114
|
+
return await this.respondError(eventData.request.id, {
|
|
115
|
+
code: 3,
|
|
116
|
+
message: error.toString(),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
await this.respond(eventData.request.id, response);
|
|
120
|
+
} else if (eventData.response && eventData.response.id) {
|
|
121
|
+
if (!this.responseHandler[eventData.response.id]) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (eventData.response.error) {
|
|
125
|
+
this.responseHandler[eventData.response.id].reject(
|
|
126
|
+
eventData.response.error
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
130
|
+
this.responseHandler[eventData.response.id].resolve(
|
|
131
|
+
eventData.response.payload as any
|
|
132
|
+
);
|
|
133
|
+
delete this.responseHandler[eventData.response.id];
|
|
134
|
+
} else {
|
|
135
|
+
return await this.respondError(-1, {
|
|
136
|
+
code: 3,
|
|
137
|
+
message: "unknown request id",
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public request<Params, Result>(
|
|
144
|
+
method: string,
|
|
145
|
+
params: Params,
|
|
146
|
+
authorization?: string
|
|
147
|
+
): Promise<Result> {
|
|
148
|
+
return new Promise<Result>((resolve, reject) => {
|
|
149
|
+
const requestId = ++this.nxtRequestId;
|
|
150
|
+
this.responseHandler[requestId] = {
|
|
151
|
+
resolve: (result) => resolve(result as Result),
|
|
152
|
+
reject: (error: SocketError) => reject(error),
|
|
153
|
+
};
|
|
154
|
+
const toSend: SocketMessage = {
|
|
155
|
+
request: {
|
|
156
|
+
method,
|
|
157
|
+
payload: params,
|
|
158
|
+
id: requestId,
|
|
159
|
+
setAuthorization: authorization,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
this.ws.send(JSON.stringify(toSend));
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private async respond<Result>(
|
|
167
|
+
requestId: number,
|
|
168
|
+
result: Result
|
|
169
|
+
): Promise<void> {
|
|
170
|
+
const toSend: SocketMessage = {
|
|
171
|
+
response: {
|
|
172
|
+
payload: result,
|
|
173
|
+
id: requestId,
|
|
174
|
+
error: null,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
return this.ws.send(JSON.stringify(toSend));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private async respondError(
|
|
181
|
+
requestId: number,
|
|
182
|
+
error: SocketError
|
|
183
|
+
): Promise<void> {
|
|
184
|
+
const toSend: SocketMessage = {
|
|
185
|
+
response: {
|
|
186
|
+
payload: null,
|
|
187
|
+
id: requestId,
|
|
188
|
+
error: error,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
return this.ws.send(JSON.stringify(toSend));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public close(): void {
|
|
195
|
+
this.ws.close();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const proxyTarget = Object.freeze(() => {
|
|
200
|
+
/* return nothing */
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
function createIsocketProxy<
|
|
204
|
+
ImplementedMethods,
|
|
205
|
+
CallableMethods,
|
|
206
|
+
RequestContext
|
|
207
|
+
>(
|
|
208
|
+
socket: ISocket<ImplementedMethods, CallableMethods, RequestContext>,
|
|
209
|
+
// if path is undefined, it means the current object is the root object
|
|
210
|
+
path: string | undefined
|
|
211
|
+
): unknown {
|
|
212
|
+
return new Proxy(proxyTarget, {
|
|
213
|
+
get(_target, prop: string) {
|
|
214
|
+
const childPath = path ? `${path}.${prop}` : prop;
|
|
215
|
+
// sometimes, when `createISocketClient` is called from an async function, JS will implicitly call the `then` method on
|
|
216
|
+
// its return value, because promises can be arbitrarily nested
|
|
217
|
+
// so return undefined for the `then` method to avoid this
|
|
218
|
+
if (childPath === "then") {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
return createIsocketProxy(socket, childPath);
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
apply(_target, _thisArg, args: unknown[]) {
|
|
225
|
+
if (path === undefined) {
|
|
226
|
+
throw new Error("The root object is not callable");
|
|
227
|
+
}
|
|
228
|
+
if (
|
|
229
|
+
path.endsWith(".apply") &&
|
|
230
|
+
args.length === 2 &&
|
|
231
|
+
Array.isArray(args[1])
|
|
232
|
+
) {
|
|
233
|
+
path = path.slice(0, -".apply".length);
|
|
234
|
+
args = args[1];
|
|
235
|
+
}
|
|
236
|
+
return socket.request(path, args[0]);
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function createISocketClient<
|
|
242
|
+
CallableMethods,
|
|
243
|
+
ImplementedMethods,
|
|
244
|
+
RequestContext
|
|
245
|
+
>(
|
|
246
|
+
socket: ISocket<ImplementedMethods, CallableMethods, RequestContext>
|
|
247
|
+
): ISocketClient<CallableMethods> {
|
|
248
|
+
return {
|
|
249
|
+
close: () => socket.close(),
|
|
250
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment
|
|
251
|
+
call: createIsocketProxy(socket, undefined) as any,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
export interface UserMeDto {
|
|
2
|
+
user: User;
|
|
3
|
+
organizations: Organization[];
|
|
4
|
+
agents: Agent[];
|
|
5
|
+
flagBootstrap: FlagBootstrap;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface FlagBootstrap {
|
|
9
|
+
"ui.enable-resource-signing"?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type User = {
|
|
13
|
+
id: string;
|
|
14
|
+
email: string;
|
|
15
|
+
currentOrganizationId: string;
|
|
16
|
+
organizationIds: string[];
|
|
17
|
+
username: string;
|
|
18
|
+
name: string;
|
|
19
|
+
anonymousId: string;
|
|
20
|
+
isAnonymous: boolean;
|
|
21
|
+
isAdmin: boolean;
|
|
22
|
+
metadata: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export interface Organization {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
displayName: string;
|
|
29
|
+
agents?: Agent[];
|
|
30
|
+
apiKey: string;
|
|
31
|
+
agentType: AgentType;
|
|
32
|
+
minExternalAgentVersion: string;
|
|
33
|
+
profiles?: Profile[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type Agent = {
|
|
37
|
+
id: string;
|
|
38
|
+
key: string;
|
|
39
|
+
environment: string;
|
|
40
|
+
status: AgentStatus;
|
|
41
|
+
version: string;
|
|
42
|
+
versionExternal: string;
|
|
43
|
+
url: string;
|
|
44
|
+
type: AgentType;
|
|
45
|
+
updated: Date;
|
|
46
|
+
created: Date;
|
|
47
|
+
tags: AgentTags;
|
|
48
|
+
verificationKeyIds?: null | string[];
|
|
49
|
+
signingKeyId?: null | string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export enum AgentStatus {
|
|
53
|
+
ACTIVE = "Active",
|
|
54
|
+
DISCONNECTED = "Disconnected",
|
|
55
|
+
BROWSER_UNREACHABLE = "Browser Unreachable",
|
|
56
|
+
// TODO: remove PENDING_REGISTRATION after the DB migration
|
|
57
|
+
PENDING_REGISTRATION = "Pending Registration",
|
|
58
|
+
STALE = "Stale",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export enum AgentType {
|
|
62
|
+
MULTITENANT = 0,
|
|
63
|
+
DEDICATED = 1,
|
|
64
|
+
ONPREMISE = 2,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type AgentTags = Record<string, string[]>;
|
|
68
|
+
|
|
69
|
+
export class Profile {
|
|
70
|
+
id: string;
|
|
71
|
+
key: string;
|
|
72
|
+
displayName: string;
|
|
73
|
+
description: string;
|
|
74
|
+
type: ProfileType;
|
|
75
|
+
|
|
76
|
+
constructor({
|
|
77
|
+
id,
|
|
78
|
+
key,
|
|
79
|
+
displayName,
|
|
80
|
+
description,
|
|
81
|
+
type,
|
|
82
|
+
}: {
|
|
83
|
+
id: string;
|
|
84
|
+
key: string;
|
|
85
|
+
displayName: string;
|
|
86
|
+
description: string;
|
|
87
|
+
type: ProfileType;
|
|
88
|
+
}) {
|
|
89
|
+
this.id = id;
|
|
90
|
+
this.key = key;
|
|
91
|
+
this.displayName = displayName;
|
|
92
|
+
this.description = description;
|
|
93
|
+
this.type = type;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export enum ProfileType {
|
|
98
|
+
RESERVED = "RESERVED",
|
|
99
|
+
CUSTOM = "CUSTOM",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export type Api = {
|
|
103
|
+
metadata: {
|
|
104
|
+
name: string;
|
|
105
|
+
id: string;
|
|
106
|
+
organization: string;
|
|
107
|
+
timestamps?: {
|
|
108
|
+
created: string;
|
|
109
|
+
updated: string;
|
|
110
|
+
deactivated: boolean;
|
|
111
|
+
};
|
|
112
|
+
// These properties are merged in from the v3 api entity
|
|
113
|
+
creator?: {
|
|
114
|
+
id: string;
|
|
115
|
+
name: string;
|
|
116
|
+
};
|
|
117
|
+
folder?: string;
|
|
118
|
+
};
|
|
119
|
+
blocks?: any[];
|
|
120
|
+
trigger: any;
|
|
121
|
+
signature?: Signature;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/** A signature, as produced by the agent. */
|
|
125
|
+
export interface Signature {
|
|
126
|
+
/** The id of the key used to sign the data. */
|
|
127
|
+
keyId: string;
|
|
128
|
+
/** The actual signature, in base64. */
|
|
129
|
+
data: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface RemoteCommitDto {
|
|
133
|
+
commitId: string;
|
|
134
|
+
remoteCommitId: string;
|
|
135
|
+
remoteCommitDate: Date;
|
|
136
|
+
branchName: string;
|
|
137
|
+
repositoryId: string;
|
|
138
|
+
}
|