@superblocksteam/sdk 1.4.2 → 1.5.1
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 +191 -82
- package/dist/flag.d.ts +2 -0
- package/dist/flag.js +7 -0
- package/dist/sdk.d.ts +5 -5
- package/dist/socket/handlers.d.ts +105 -0
- package/dist/socket/handlers.js +97 -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 +70 -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 +66 -0
- package/package.json +5 -3
- package/src/client.ts +179 -51
- package/src/flag.ts +5 -0
- package/src/sdk.ts +8 -8
- package/src/socket/handlers.ts +248 -0
- package/src/socket/index.ts +164 -0
- package/src/socket/signing.ts +104 -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 +81 -0
- package/tsconfig.json +3 -1
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ApiToSign, ApiToVerify, AppToSign, AppToVerify, MethodHandlers, RemoteCommitDto, Signature } from "../types";
|
|
2
|
+
type MethodSchema<Params, Response> = (params: Params) => Promise<Response>;
|
|
3
|
+
export interface ClientMethods {
|
|
4
|
+
v1: {
|
|
5
|
+
signing: {
|
|
6
|
+
signApplication: MethodSchema<{
|
|
7
|
+
branchName: string;
|
|
8
|
+
toSign: AppToSign;
|
|
9
|
+
}, {
|
|
10
|
+
signature: Signature;
|
|
11
|
+
}>;
|
|
12
|
+
signApis: MethodSchema<{
|
|
13
|
+
branchName: string;
|
|
14
|
+
toSign: ApiToSign[];
|
|
15
|
+
}, {
|
|
16
|
+
signatures: Signature[];
|
|
17
|
+
}>;
|
|
18
|
+
verifyApplication: MethodSchema<{
|
|
19
|
+
branchName: string;
|
|
20
|
+
toVerify: AppToVerify;
|
|
21
|
+
}, {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
verifyApi: MethodSchema<{
|
|
25
|
+
branchName: string;
|
|
26
|
+
toVerify: ApiToVerify[];
|
|
27
|
+
}, {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
type ServerMethodSchema<Params, Response> = MethodSchema<Params, ResponseDto<Response>>;
|
|
34
|
+
type ResponseDto<T> = {
|
|
35
|
+
responseMeta: ResponseMeta;
|
|
36
|
+
data: T;
|
|
37
|
+
};
|
|
38
|
+
export type ResponseMeta = {
|
|
39
|
+
status: number;
|
|
40
|
+
success: boolean;
|
|
41
|
+
error?: APIResponseError;
|
|
42
|
+
};
|
|
43
|
+
type APIResponseError = {
|
|
44
|
+
code: number;
|
|
45
|
+
message: string;
|
|
46
|
+
};
|
|
47
|
+
export interface ServerMethods {
|
|
48
|
+
v1: {
|
|
49
|
+
echo: MethodSchema<{
|
|
50
|
+
message: string;
|
|
51
|
+
}, {
|
|
52
|
+
message: string;
|
|
53
|
+
}>;
|
|
54
|
+
public: {
|
|
55
|
+
application: {
|
|
56
|
+
component: {
|
|
57
|
+
register: ServerMethodSchema<{
|
|
58
|
+
applicationId: string;
|
|
59
|
+
branchName: string;
|
|
60
|
+
cliVersion: string;
|
|
61
|
+
componentEvent: string;
|
|
62
|
+
components: Record<string, unknown>;
|
|
63
|
+
}, {
|
|
64
|
+
success: boolean;
|
|
65
|
+
}>;
|
|
66
|
+
update: ServerMethodSchema<{
|
|
67
|
+
applicationId: string;
|
|
68
|
+
branchName?: string;
|
|
69
|
+
srcFiles: string[];
|
|
70
|
+
buildFiles: string[];
|
|
71
|
+
registeredComponents: Record<string, unknown>;
|
|
72
|
+
cliVersion: string | undefined;
|
|
73
|
+
componentBaseUrl: string;
|
|
74
|
+
signingRequired: boolean;
|
|
75
|
+
}, {
|
|
76
|
+
success: boolean;
|
|
77
|
+
}>;
|
|
78
|
+
};
|
|
79
|
+
pushCommit: ServerMethodSchema<{
|
|
80
|
+
applicationId: string;
|
|
81
|
+
branchName: string;
|
|
82
|
+
commitId: string;
|
|
83
|
+
commitMessage: string;
|
|
84
|
+
application: Record<string, unknown>;
|
|
85
|
+
page: Record<string, unknown>;
|
|
86
|
+
apis: Record<string, unknown>[];
|
|
87
|
+
}, RemoteCommitDto>;
|
|
88
|
+
};
|
|
89
|
+
api: {
|
|
90
|
+
pushCommit: ServerMethodSchema<{
|
|
91
|
+
apiId: string;
|
|
92
|
+
branchName: string;
|
|
93
|
+
commitId: string;
|
|
94
|
+
commitMessage: string;
|
|
95
|
+
apiPb: Record<string, unknown>;
|
|
96
|
+
}, RemoteCommitDto>;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export declare function createRequestHandlers({ agentUrl, token, }: {
|
|
102
|
+
token: string;
|
|
103
|
+
agentUrl?: string;
|
|
104
|
+
}): MethodHandlers<ClientMethods, ServerMethods, unknown>;
|
|
105
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRequestHandlers = void 0;
|
|
4
|
+
const signing_1 = require("./signing");
|
|
5
|
+
function createRequestHandlers({ agentUrl, token, }) {
|
|
6
|
+
const requestHandlers = {
|
|
7
|
+
v1: {
|
|
8
|
+
signing: {
|
|
9
|
+
signApplication: [
|
|
10
|
+
async ({ branchName, toSign, }) => {
|
|
11
|
+
if (!agentUrl) {
|
|
12
|
+
throw new Error("Agent url not specified. This shouldn't happen.");
|
|
13
|
+
}
|
|
14
|
+
const signature = await (0, signing_1.signResource)({
|
|
15
|
+
agentUrl,
|
|
16
|
+
token: token,
|
|
17
|
+
branchName,
|
|
18
|
+
resource: {
|
|
19
|
+
literal: {
|
|
20
|
+
data: toSign.rootHash,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
return { signature: signature };
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
signApis: [
|
|
28
|
+
async ({ branchName, toSign, }) => {
|
|
29
|
+
const signatures = [];
|
|
30
|
+
for (const { apiPb } of toSign) {
|
|
31
|
+
if (!agentUrl) {
|
|
32
|
+
throw new Error("Agent url not specified. This shouldn't happen.");
|
|
33
|
+
}
|
|
34
|
+
const signature = await (0, signing_1.signResource)({
|
|
35
|
+
agentUrl,
|
|
36
|
+
token: token,
|
|
37
|
+
branchName,
|
|
38
|
+
resource: { api: apiPb },
|
|
39
|
+
});
|
|
40
|
+
signatures.push(signature);
|
|
41
|
+
}
|
|
42
|
+
return { signatures };
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
verifyApplication: [
|
|
46
|
+
async ({ branchName, toVerify, }) => {
|
|
47
|
+
try {
|
|
48
|
+
if (!agentUrl) {
|
|
49
|
+
throw new Error("Agent url not specified. This shouldn't happen.");
|
|
50
|
+
}
|
|
51
|
+
await (0, signing_1.verifyResources)({
|
|
52
|
+
agentUrl,
|
|
53
|
+
token,
|
|
54
|
+
branchName,
|
|
55
|
+
resources: [
|
|
56
|
+
{
|
|
57
|
+
literal: {
|
|
58
|
+
data: toVerify.rootHash,
|
|
59
|
+
signature: toVerify.signature,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
return { ok: true };
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return { ok: false };
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
verifyApi: [
|
|
72
|
+
async ({ branchName, toVerify, }) => {
|
|
73
|
+
try {
|
|
74
|
+
if (!agentUrl) {
|
|
75
|
+
throw new Error("Agent url not specified. This shouldn't happen.");
|
|
76
|
+
}
|
|
77
|
+
await (0, signing_1.verifyResources)({
|
|
78
|
+
agentUrl,
|
|
79
|
+
token,
|
|
80
|
+
branchName,
|
|
81
|
+
resources: toVerify.map(({ apiPb }) => ({
|
|
82
|
+
api: apiPb,
|
|
83
|
+
})),
|
|
84
|
+
});
|
|
85
|
+
return { ok: true };
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return { ok: false };
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
return requestHandlers;
|
|
96
|
+
}
|
|
97
|
+
exports.createRequestHandlers = createRequestHandlers;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// <reference types="ws" />
|
|
2
|
+
import WebSocket from "isomorphic-ws";
|
|
3
|
+
import { ServerMethods } from "./handlers";
|
|
4
|
+
export type StdISocketRPCClient = ISocketClient<ServerMethods>;
|
|
5
|
+
export declare function connectToISocketRPCServer({ superblocksBaseUrl, agentUrl, token, }: {
|
|
6
|
+
superblocksBaseUrl: string;
|
|
7
|
+
token: string;
|
|
8
|
+
agentUrl?: string;
|
|
9
|
+
}): Promise<StdISocketRPCClient>;
|
|
10
|
+
export declare function connectISocket<CallableMethods, ImplementedMethods, RequestContext = never>(wsUrl: string, authorization: string | undefined, requestHandlers: MethodHandlers<ImplementedMethods, CallableMethods, RequestContext>): Promise<ISocketClient<CallableMethods>>;
|
|
11
|
+
export declare function connectWebSocket(wsUrl: string): Promise<WebSocket>;
|
|
12
|
+
type MethodHandler<Params, Result, PeerMethods, RequestContext> = (params: Params, peer: ISocketClient<PeerMethods>, ctx: RequestContext) => Promise<Result>;
|
|
13
|
+
type MiddlewareHandler<Params, PeerMethods, RequestContext> = (params: Params, peerAuthorization: string | undefined, peer: ISocketClient<PeerMethods>, ctx: RequestContext) => Promise<void>;
|
|
14
|
+
type MethodHandlers<Methods, PeerMethods, RequestContext> = {
|
|
15
|
+
[Key in keyof Methods]: Methods[Key] extends (params: infer Params) => Promise<infer Result> ? [
|
|
16
|
+
...middlewareHandlers: MiddlewareHandler<Params, PeerMethods, RequestContext>[],
|
|
17
|
+
handler: MethodHandler<Params, Result, PeerMethods, RequestContext>
|
|
18
|
+
] : Methods[Key] extends Record<string, unknown> ? MethodHandlers<Methods[Key], PeerMethods, RequestContext> : never;
|
|
19
|
+
};
|
|
20
|
+
type ISocketClientMethodCall<Methods> = {
|
|
21
|
+
[Key in keyof Methods]: Methods[Key] extends (params: infer P) => Promise<infer R> ? (params: P) => Promise<R> : Methods[Key] extends Record<string, unknown> ? ISocketClientMethodCall<Methods[Key]> : never;
|
|
22
|
+
};
|
|
23
|
+
type ISocketClient<Methods> = {
|
|
24
|
+
close: () => void;
|
|
25
|
+
call: ISocketClientMethodCall<Methods>;
|
|
26
|
+
};
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.connectWebSocket = exports.connectISocket = exports.connectToISocketRPCServer = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const isomorphic_ws_1 = tslib_1.__importDefault(require("isomorphic-ws"));
|
|
6
|
+
const handlers_1 = require("./handlers");
|
|
7
|
+
const socket_1 = require("./socket");
|
|
8
|
+
async function connectToISocketRPCServer({ superblocksBaseUrl, agentUrl, token, }) {
|
|
9
|
+
const requestHandlers = (0, handlers_1.createRequestHandlers)({
|
|
10
|
+
agentUrl,
|
|
11
|
+
token,
|
|
12
|
+
});
|
|
13
|
+
const authorization = `Bearer ${token}`;
|
|
14
|
+
const wsUrl = new URL("api/v1/rpc-ws", superblocksBaseUrl);
|
|
15
|
+
if (wsUrl.protocol === "http:") {
|
|
16
|
+
wsUrl.protocol = "ws:";
|
|
17
|
+
}
|
|
18
|
+
else if (wsUrl.protocol === "https:") {
|
|
19
|
+
wsUrl.protocol = "wss:";
|
|
20
|
+
}
|
|
21
|
+
if (wsUrl.host === "localhost:3000") {
|
|
22
|
+
wsUrl.host = "127.0.0.1:8080";
|
|
23
|
+
}
|
|
24
|
+
else if (wsUrl.hostname === "localhost") {
|
|
25
|
+
wsUrl.hostname = "127.0.0.1";
|
|
26
|
+
}
|
|
27
|
+
return await connectISocket(wsUrl.href, authorization, requestHandlers);
|
|
28
|
+
}
|
|
29
|
+
exports.connectToISocketRPCServer = connectToISocketRPCServer;
|
|
30
|
+
// a subclass of ISocket that sends an auth token on the first request
|
|
31
|
+
// this is useful for client-side sockets that need to authenticate
|
|
32
|
+
// TODO(george): if we start using this for long-lived connections, we should add a way to refresh the token
|
|
33
|
+
class ISocketWithClientAuth extends socket_1.ISocket {
|
|
34
|
+
constructor(ws, authorization, requestHandlers) {
|
|
35
|
+
super(ws, requestHandlers);
|
|
36
|
+
this.hasSentAuth = false;
|
|
37
|
+
this.authorization = authorization;
|
|
38
|
+
}
|
|
39
|
+
// override `request` from the base class to send `authorization` when appropriate
|
|
40
|
+
async request(method, params) {
|
|
41
|
+
// only send `authorization` on the first request
|
|
42
|
+
const authorization = this.hasSentAuth ? undefined : this.authorization;
|
|
43
|
+
const result = await super.request(method, params, authorization);
|
|
44
|
+
this.hasSentAuth = true;
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function connectISocket(wsUrl, authorization, requestHandlers) {
|
|
49
|
+
const ws = await connectWebSocket(wsUrl);
|
|
50
|
+
const isocket = new ISocketWithClientAuth(ws, authorization, requestHandlers);
|
|
51
|
+
return (0, socket_1.createISocketClient)(isocket);
|
|
52
|
+
}
|
|
53
|
+
exports.connectISocket = connectISocket;
|
|
54
|
+
function connectWebSocket(wsUrl) {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const ws = new isomorphic_ws_1.default(wsUrl);
|
|
57
|
+
ws.addEventListener("open", () => {
|
|
58
|
+
// Resolve the promise with the WebSocket instance when the connection is open
|
|
59
|
+
resolve(ws);
|
|
60
|
+
});
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
ws.addEventListener("error", (error) => {
|
|
64
|
+
// Reject the promise if there's an error
|
|
65
|
+
reject(error);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
exports.connectWebSocket = connectWebSocket;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ApiResource, GenericResource, Signature } from "../types";
|
|
2
|
+
export declare function signResource({ token, branchName, resource, agentUrl, }: {
|
|
3
|
+
token: string;
|
|
4
|
+
branchName: string;
|
|
5
|
+
resource: ApiResource | GenericResource;
|
|
6
|
+
agentUrl: string;
|
|
7
|
+
}): Promise<Signature>;
|
|
8
|
+
export declare function verifyResources({ agentUrl, token, branchName, resources, }: {
|
|
9
|
+
resources: Array<GenericResource | ApiResource>;
|
|
10
|
+
token: string;
|
|
11
|
+
branchName: string;
|
|
12
|
+
agentUrl: string;
|
|
13
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyResources = exports.signResource = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const axios_1 = tslib_1.__importDefault(require("axios"));
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
async function signResource({ token, branchName, resource, agentUrl, }) {
|
|
8
|
+
const requestResource = {
|
|
9
|
+
branchName: branchName ?? "main",
|
|
10
|
+
};
|
|
11
|
+
if (resource.api) {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
13
|
+
requestResource.api = (0, utils_1.getSanitizedApi)(resource.api);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
requestResource.literal = resource.literal;
|
|
17
|
+
}
|
|
18
|
+
const resp = await callAgent({
|
|
19
|
+
baseUrl: agentUrl,
|
|
20
|
+
path: "v1/signature/sign",
|
|
21
|
+
method: "post",
|
|
22
|
+
token: token,
|
|
23
|
+
data: { resource: requestResource },
|
|
24
|
+
});
|
|
25
|
+
return resp.signature;
|
|
26
|
+
}
|
|
27
|
+
exports.signResource = signResource;
|
|
28
|
+
async function verifyResources({ agentUrl, token, branchName, resources, }) {
|
|
29
|
+
await callAgent({
|
|
30
|
+
baseUrl: agentUrl,
|
|
31
|
+
path: "v1/signature/verify",
|
|
32
|
+
method: "post",
|
|
33
|
+
token: token,
|
|
34
|
+
data: {
|
|
35
|
+
resources: resources.map((res) => {
|
|
36
|
+
if (res.api) {
|
|
37
|
+
return {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
39
|
+
api: (0, utils_1.getSanitizedApi)(res.api),
|
|
40
|
+
branchName: branchName ?? "main",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
...res,
|
|
45
|
+
branchName: branchName ?? "main",
|
|
46
|
+
};
|
|
47
|
+
}),
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
exports.verifyResources = verifyResources;
|
|
52
|
+
async function callAgent({ baseUrl, path, method, token, data, }) {
|
|
53
|
+
try {
|
|
54
|
+
const url = new URL(path, baseUrl);
|
|
55
|
+
const config = {
|
|
56
|
+
url: url.toString(),
|
|
57
|
+
method: method,
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: "Bearer " + token,
|
|
60
|
+
},
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
62
|
+
data: data,
|
|
63
|
+
};
|
|
64
|
+
const resp = await (0, axios_1.default)(config);
|
|
65
|
+
return resp.data;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw new Error(`Failed to request the agent ${baseUrl}. Error: ${error}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="ws" />
|
|
2
|
+
import WebSocket from "isomorphic-ws";
|
|
3
|
+
import { ISocketClient, MethodHandlers } from "../types";
|
|
4
|
+
export declare class ISocket<ImplementedMethods, CallableMethods, RequestContext> {
|
|
5
|
+
private readonly ws;
|
|
6
|
+
private readonly requestHandlers;
|
|
7
|
+
private readonly responseHandler;
|
|
8
|
+
private peerAuthorization?;
|
|
9
|
+
private nxtRequestId;
|
|
10
|
+
constructor(ws: WebSocket, requestHandlers: MethodHandlers<ImplementedMethods, CallableMethods, RequestContext>);
|
|
11
|
+
request<Params, Result>(method: string, params: Params, authorization?: string): Promise<Result>;
|
|
12
|
+
private respond;
|
|
13
|
+
private respondError;
|
|
14
|
+
close(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function createISocketClient<CallableMethods, ImplementedMethods, RequestContext>(socket: ISocket<ImplementedMethods, CallableMethods, RequestContext>): ISocketClient<CallableMethods>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createISocketClient = exports.ISocket = void 0;
|
|
4
|
+
class ISocket {
|
|
5
|
+
constructor(ws, requestHandlers) {
|
|
6
|
+
this.responseHandler = {};
|
|
7
|
+
this.ws = ws;
|
|
8
|
+
this.requestHandlers = requestHandlers;
|
|
9
|
+
this.nxtRequestId = 0;
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
this.ws.addEventListener("message", async (event) => {
|
|
13
|
+
const eventData = JSON.parse(event.data.toString());
|
|
14
|
+
if (eventData.request) {
|
|
15
|
+
// Split the method string into parts
|
|
16
|
+
const parts = eventData.request.method.split(".");
|
|
17
|
+
let handlers = this.requestHandlers;
|
|
18
|
+
for (const part of parts) {
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
handlers = handlers[part];
|
|
21
|
+
if (!handlers) {
|
|
22
|
+
return await this.respondError(eventData.request.id, {
|
|
23
|
+
code: 2,
|
|
24
|
+
message: `unknown method ${eventData.request.method}`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (!Array.isArray(handlers)) {
|
|
29
|
+
return await this.respondError(eventData.request.id, {
|
|
30
|
+
code: 2,
|
|
31
|
+
message: "unknown method",
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (eventData.request.setAuthorization) {
|
|
35
|
+
this.peerAuthorization = eventData.request.setAuthorization;
|
|
36
|
+
}
|
|
37
|
+
const middlewareHandlers = handlers.slice(0, -1);
|
|
38
|
+
const handler = handlers[handlers.length - 1];
|
|
39
|
+
const reqCtx = {};
|
|
40
|
+
let response;
|
|
41
|
+
// TODO(george): maybe we should not create a new client for each request
|
|
42
|
+
const client = createISocketClient(this);
|
|
43
|
+
try {
|
|
44
|
+
for (const middlewareHandler of middlewareHandlers) {
|
|
45
|
+
await middlewareHandler(eventData.request.payload, this.peerAuthorization, client, reqCtx);
|
|
46
|
+
}
|
|
47
|
+
response = await handler(eventData.request.payload, client, reqCtx);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return await this.respondError(eventData.request.id, {
|
|
51
|
+
code: 3,
|
|
52
|
+
message: error.toString(),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
await this.respond(eventData.request.id, response);
|
|
56
|
+
}
|
|
57
|
+
else if (eventData.response && eventData.response.id) {
|
|
58
|
+
if (!this.responseHandler[eventData.response.id]) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (eventData.response.error) {
|
|
62
|
+
this.responseHandler[eventData.response.id].reject(eventData.response.error);
|
|
63
|
+
}
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
this.responseHandler[eventData.response.id].resolve(eventData.response.payload);
|
|
66
|
+
delete this.responseHandler[eventData.response.id];
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
return await this.respondError(-1, {
|
|
70
|
+
code: 3,
|
|
71
|
+
message: "unknown request id",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
request(method, params, authorization) {
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
const requestId = ++this.nxtRequestId;
|
|
79
|
+
this.responseHandler[requestId] = {
|
|
80
|
+
resolve: (result) => resolve(result),
|
|
81
|
+
reject: (error) => reject(error),
|
|
82
|
+
};
|
|
83
|
+
const toSend = {
|
|
84
|
+
request: {
|
|
85
|
+
method,
|
|
86
|
+
payload: params,
|
|
87
|
+
id: requestId,
|
|
88
|
+
setAuthorization: authorization,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
this.ws.send(JSON.stringify(toSend));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async respond(requestId, result) {
|
|
95
|
+
const toSend = {
|
|
96
|
+
response: {
|
|
97
|
+
payload: result,
|
|
98
|
+
id: requestId,
|
|
99
|
+
error: null,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
return this.ws.send(JSON.stringify(toSend));
|
|
103
|
+
}
|
|
104
|
+
async respondError(requestId, error) {
|
|
105
|
+
const toSend = {
|
|
106
|
+
response: {
|
|
107
|
+
payload: null,
|
|
108
|
+
id: requestId,
|
|
109
|
+
error: error,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
return this.ws.send(JSON.stringify(toSend));
|
|
113
|
+
}
|
|
114
|
+
close() {
|
|
115
|
+
this.ws.close();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.ISocket = ISocket;
|
|
119
|
+
const proxyTarget = Object.freeze(() => {
|
|
120
|
+
/* return nothing */
|
|
121
|
+
});
|
|
122
|
+
function createIsocketProxy(socket,
|
|
123
|
+
// if path is undefined, it means the current object is the root object
|
|
124
|
+
path) {
|
|
125
|
+
return new Proxy(proxyTarget, {
|
|
126
|
+
get(_target, prop) {
|
|
127
|
+
const childPath = path ? `${path}.${prop}` : prop;
|
|
128
|
+
// sometimes, when `createISocketClient` is called from an async function, JS will implicitly call the `then` method on
|
|
129
|
+
// its return value, because promises can be arbitrarily nested
|
|
130
|
+
// so return undefined for the `then` method to avoid this
|
|
131
|
+
if (childPath === "then") {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
return createIsocketProxy(socket, childPath);
|
|
135
|
+
},
|
|
136
|
+
apply(_target, _thisArg, args) {
|
|
137
|
+
if (path === undefined) {
|
|
138
|
+
throw new Error("The root object is not callable");
|
|
139
|
+
}
|
|
140
|
+
if (path.endsWith(".apply") &&
|
|
141
|
+
args.length === 2 &&
|
|
142
|
+
Array.isArray(args[1])) {
|
|
143
|
+
path = path.slice(0, -".apply".length);
|
|
144
|
+
args = args[1];
|
|
145
|
+
}
|
|
146
|
+
return socket.request(path, args[0]);
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
function createISocketClient(socket) {
|
|
151
|
+
return {
|
|
152
|
+
close: () => socket.close(),
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment
|
|
154
|
+
call: createIsocketProxy(socket, undefined),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
exports.createISocketClient = createISocketClient;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export interface UserMeDto {
|
|
2
|
+
user: User;
|
|
3
|
+
organizations: Organization[];
|
|
4
|
+
agents: Agent[];
|
|
5
|
+
flagBootstrap: FlagBootstrap;
|
|
6
|
+
}
|
|
7
|
+
export interface FlagBootstrap {
|
|
8
|
+
"ui.enable-resource-signing"?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export type User = {
|
|
11
|
+
id: string;
|
|
12
|
+
email: string;
|
|
13
|
+
currentOrganizationId: string;
|
|
14
|
+
organizationIds: string[];
|
|
15
|
+
username: string;
|
|
16
|
+
name: string;
|
|
17
|
+
anonymousId: string;
|
|
18
|
+
isAnonymous: boolean;
|
|
19
|
+
isAdmin: boolean;
|
|
20
|
+
metadata: Record<string, unknown>;
|
|
21
|
+
};
|
|
22
|
+
export interface Organization {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
displayName: string;
|
|
26
|
+
agents?: Agent[];
|
|
27
|
+
apiKey: string;
|
|
28
|
+
agentType: AgentType;
|
|
29
|
+
minExternalAgentVersion: string;
|
|
30
|
+
profiles?: Profile[];
|
|
31
|
+
}
|
|
32
|
+
export type Agent = {
|
|
33
|
+
id: string;
|
|
34
|
+
key: string;
|
|
35
|
+
environment: string;
|
|
36
|
+
status: AgentStatus;
|
|
37
|
+
version: string;
|
|
38
|
+
versionExternal: string;
|
|
39
|
+
url: string;
|
|
40
|
+
type: AgentType;
|
|
41
|
+
updated: Date;
|
|
42
|
+
created: Date;
|
|
43
|
+
tags: AgentTags;
|
|
44
|
+
verificationKeyIds?: null | string[];
|
|
45
|
+
signingKeyId?: null | string;
|
|
46
|
+
};
|
|
47
|
+
export declare enum AgentStatus {
|
|
48
|
+
ACTIVE = "Active",
|
|
49
|
+
DISCONNECTED = "Disconnected",
|
|
50
|
+
BROWSER_UNREACHABLE = "Browser Unreachable",
|
|
51
|
+
PENDING_REGISTRATION = "Pending Registration",
|
|
52
|
+
STALE = "Stale"
|
|
53
|
+
}
|
|
54
|
+
export declare enum AgentType {
|
|
55
|
+
MULTITENANT = 0,
|
|
56
|
+
DEDICATED = 1,
|
|
57
|
+
ONPREMISE = 2
|
|
58
|
+
}
|
|
59
|
+
export type AgentTags = Record<string, string[]>;
|
|
60
|
+
export declare class Profile {
|
|
61
|
+
id: string;
|
|
62
|
+
key: string;
|
|
63
|
+
displayName: string;
|
|
64
|
+
description: string;
|
|
65
|
+
type: ProfileType;
|
|
66
|
+
constructor({ id, key, displayName, description, type, }: {
|
|
67
|
+
id: string;
|
|
68
|
+
key: string;
|
|
69
|
+
displayName: string;
|
|
70
|
+
description: string;
|
|
71
|
+
type: ProfileType;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
export declare enum ProfileType {
|
|
75
|
+
RESERVED = "RESERVED",
|
|
76
|
+
CUSTOM = "CUSTOM"
|
|
77
|
+
}
|
|
78
|
+
export type Api = {
|
|
79
|
+
metadata: {
|
|
80
|
+
name: string;
|
|
81
|
+
id: string;
|
|
82
|
+
organization: string;
|
|
83
|
+
timestamps?: {
|
|
84
|
+
created: string;
|
|
85
|
+
updated: string;
|
|
86
|
+
deactivated: boolean;
|
|
87
|
+
};
|
|
88
|
+
creator?: {
|
|
89
|
+
id: string;
|
|
90
|
+
name: string;
|
|
91
|
+
};
|
|
92
|
+
folder?: string;
|
|
93
|
+
};
|
|
94
|
+
blocks?: any[];
|
|
95
|
+
trigger: any;
|
|
96
|
+
signature?: Signature;
|
|
97
|
+
};
|
|
98
|
+
/** A signature, as produced by the agent. */
|
|
99
|
+
export interface Signature {
|
|
100
|
+
/** The id of the key used to sign the data. */
|
|
101
|
+
keyId: string;
|
|
102
|
+
/** The actual signature, in base64. */
|
|
103
|
+
data: string;
|
|
104
|
+
}
|
|
105
|
+
export interface RemoteCommitDto {
|
|
106
|
+
commitId: string;
|
|
107
|
+
remoteCommitId: string;
|
|
108
|
+
remoteCommitDate: Date;
|
|
109
|
+
branchName: string;
|
|
110
|
+
repositoryId: string;
|
|
111
|
+
}
|