@superblocksteam/sdk 1.5.0 → 1.5.2

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.
@@ -4,9 +4,9 @@ exports.verifyResources = exports.signResource = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const axios_1 = tslib_1.__importDefault(require("axios"));
6
6
  const utils_1 = require("../utils");
7
- async function signResource({ token, branchName, resource, agentUrls, }) {
7
+ async function signResource({ token, branchName, resource, agentUrl, }) {
8
8
  const requestResource = {
9
- branchName: branchName !== null && branchName !== void 0 ? branchName : "main",
9
+ branchName: branchName ?? "main",
10
10
  };
11
11
  if (resource.api) {
12
12
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -15,67 +15,56 @@ async function signResource({ token, branchName, resource, agentUrls, }) {
15
15
  else {
16
16
  requestResource.literal = resource.literal;
17
17
  }
18
- try {
19
- const resp = await callAgentFallBack({
20
- baseUrls: agentUrls,
21
- path: "v1/signature/sign",
22
- method: "post",
23
- token: token,
24
- data: { resource: requestResource },
25
- });
26
- return resp.signature;
27
- }
28
- catch (e) {
29
- throw new Error("No agents available to sign the resource");
30
- }
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;
31
26
  }
32
27
  exports.signResource = signResource;
33
- async function verifyResources({ agentUrls, token, branchName, resources, }) {
34
- try {
35
- await callAgentFallBack({
36
- baseUrls: agentUrls,
37
- path: "v1/signature/verify",
38
- method: "post",
39
- token: token,
40
- data: {
41
- resources: resources.map((res) => {
42
- if (res.api) {
43
- return {
44
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
45
- api: (0, utils_1.getSanitizedApi)(res.api),
46
- branchName: branchName !== null && branchName !== void 0 ? branchName : "main",
47
- };
48
- }
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) {
49
37
  return {
50
- ...res,
51
- branchName: branchName !== null && branchName !== void 0 ? branchName : "main",
38
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
39
+ api: (0, utils_1.getSanitizedApi)(res.api),
40
+ branchName: branchName ?? "main",
52
41
  };
53
- }),
54
- },
55
- });
56
- }
57
- catch (e) {
58
- throw new Error("No agents available to verify the resource");
59
- }
42
+ }
43
+ return {
44
+ ...res,
45
+ branchName: branchName ?? "main",
46
+ };
47
+ }),
48
+ },
49
+ });
60
50
  }
61
51
  exports.verifyResources = verifyResources;
62
- async function callAgentFallBack({ baseUrls, path, method, token, data, }) {
63
- for (const baseUrl of baseUrls) {
64
- try {
65
- const url = new URL(path, baseUrl);
66
- const config = {
67
- url: url.toString(),
68
- method: method,
69
- headers: {
70
- Authorization: "Bearer " + token,
71
- },
72
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
73
- data: data,
74
- };
75
- const resp = await (0, axios_1.default)(config);
76
- return resp.data;
77
- }
78
- catch (e) { }
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}`);
79
69
  }
80
- throw new Error("Failed to request ");
81
70
  }
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Agent, AgentType, Api } from "./types";
2
- export declare function getAgentUrls(agents: Agent[], agentType: AgentType): string[];
2
+ export declare function getAgentUrl(agents: Agent[], agentType: AgentType, profile?: string, healthCheck?: boolean): Promise<string>;
3
3
  export declare const sanitizeV2RequestBody: (apiBody: Record<string, unknown>) => Record<string, unknown>;
4
4
  export declare const getSanitizedApi: (api: Api) => any;
package/dist/utils.js CHANGED
@@ -1,12 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSanitizedApi = exports.sanitizeV2RequestBody = exports.getAgentUrls = void 0;
3
+ exports.getSanitizedApi = exports.sanitizeV2RequestBody = exports.getAgentUrl = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const axios_1 = tslib_1.__importDefault(require("axios"));
4
6
  const types_1 = require("./types");
5
- function getAgentUrls(agents, agentType) {
6
- const filtered = agents.filter((a) => a.type === agentType && a.status === types_1.AgentStatus.ACTIVE);
7
- return filtered.map((f) => f.url);
7
+ async function getAgentUrl(agents, agentType, profile, healthCheck = true) {
8
+ let filtered = agents.filter((a) => a.type === agentType && a.status === types_1.AgentStatus.ACTIVE);
9
+ if (profile) {
10
+ filtered = agents.filter((a) => a.tags.profile &&
11
+ (a.tags.profile.includes("*") || a.tags.profile.includes(profile)));
12
+ }
13
+ if (healthCheck) {
14
+ const coroutines = [];
15
+ for (const agent of filtered) {
16
+ const p = (async () => {
17
+ const url = new URL("health", agent.url);
18
+ const config = {
19
+ url: url.toString(),
20
+ method: "get",
21
+ headers: {},
22
+ };
23
+ await (0, axios_1.default)(config);
24
+ return agent.url;
25
+ })();
26
+ coroutines.push(p);
27
+ }
28
+ try {
29
+ return await Promise.any(coroutines);
30
+ }
31
+ catch (e) {
32
+ throw new Error("No available agents");
33
+ }
34
+ }
35
+ else {
36
+ const randomIndex = Math.floor(Math.random() * filtered.length);
37
+ return filtered[randomIndex].url;
38
+ }
8
39
  }
9
- exports.getAgentUrls = getAgentUrls;
40
+ exports.getAgentUrl = getAgentUrl;
10
41
  const sanitizeV2RequestBody = (apiBody) => {
11
42
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
43
  const traverseJSON = (obj) => {
@@ -26,8 +57,7 @@ const sanitizeV2RequestBody = (apiBody) => {
26
57
  };
27
58
  exports.sanitizeV2RequestBody = sanitizeV2RequestBody;
28
59
  const getSanitizedApi = (api) => {
29
- var _a, _b;
30
- const sanitizedBlocks = (_b = ((_a = api.blocks) !== null && _a !== void 0 ? _a : [])) === null || _b === void 0 ? void 0 : _b.map((block) => (0, exports.sanitizeV2RequestBody)(block));
60
+ const sanitizedBlocks = (api.blocks ?? [])?.map((block) => (0, exports.sanitizeV2RequestBody)(block));
31
61
  return {
32
62
  ...api,
33
63
  blocks: sanitizedBlocks,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superblocksteam/sdk",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "Superblocks JS SDK",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
@@ -31,7 +31,7 @@
31
31
  "typescript": "^5.1.3"
32
32
  },
33
33
  "dependencies": {
34
- "@superblocksteam/util": "1.5.0",
34
+ "@superblocksteam/util": "1.5.2",
35
35
  "axios": "^1.3.5",
36
36
  "isomorphic-ws": "^5.0.0"
37
37
  },
package/src/client.ts CHANGED
@@ -17,7 +17,7 @@ import { BranchNotCheckedOutError, CommitAlreadyExistsError } from "./errors";
17
17
  import { signingEnabled } from "./flag";
18
18
  import { connectToISocketRPCServer } from "./socket";
19
19
  import { AgentType, RemoteCommitDto, UserMeDto } from "./types";
20
- import { getAgentUrls } from "./utils";
20
+ import { getAgentUrl } from "./utils";
21
21
 
22
22
  const BASE_BUCKETEER_URL = "api";
23
23
  const BASE_SERVER_PUBLIC_API_URL = "api/v1/public";
@@ -422,10 +422,18 @@ export async function registerComponents(
422
422
  superblocksBaseUrl
423
423
  );
424
424
  const organization = userMe.organizations[0];
425
- if (organization.agentType == AgentType.ONPREMISE && signingEnabled(userMe.flagBootstrap)) {
426
- const agentUrls = getAgentUrls(userMe.agents, organization.agentType);
425
+ if (
426
+ organization.agentType == AgentType.ONPREMISE &&
427
+ signingEnabled(userMe.flagBootstrap)
428
+ ) {
429
+ const profile = process.env.SUPERBLOCKS_PROFILE;
430
+ const agentUrl = await getAgentUrl(
431
+ userMe.agents,
432
+ organization.agentType,
433
+ profile
434
+ );
427
435
  const socket = await connectToISocketRPCServer({
428
- agentUrls,
436
+ agentUrl,
429
437
  superblocksBaseUrl,
430
438
  token,
431
439
  });
@@ -554,7 +562,7 @@ You can reduce your component bundle size by uploading static assets to a separa
554
562
  [CLI_VERSION_HEADER]: cliVersion,
555
563
  [COMPONENT_EVENT_HEADER]: ComponentEvent.UPLOAD,
556
564
  [SUPERBLOCKS_URL_HEADER]: superblocksBaseUrl,
557
- ...formHeaders,
565
+ ...formHeaders,
558
566
  },
559
567
  };
560
568
 
@@ -566,13 +574,15 @@ You can reduce your component bundle size by uploading static assets to a separa
566
574
  superblocksBaseUrl
567
575
  );
568
576
  const organization = userMe.organizations[0];
569
- const signingRequired = organization.agentType == AgentType.ONPREMISE && signingEnabled(userMe.flagBootstrap);
570
- let agentUrls: string[] = [];
577
+ let agentUrl: string | undefined;
578
+ const signingRequired =
579
+ organization.agentType == AgentType.ONPREMISE &&
580
+ signingEnabled(userMe.flagBootstrap);
571
581
  if (signingRequired) {
572
- agentUrls = getAgentUrls(userMe.agents, organization.agentType);
582
+ agentUrl = await getAgentUrl(userMe.agents, organization.agentType);
573
583
  }
574
584
  const socket = await connectToISocketRPCServer({
575
- agentUrls,
585
+ agentUrl,
576
586
  superblocksBaseUrl,
577
587
  token,
578
588
  });
@@ -665,14 +675,15 @@ export async function pushApplication({
665
675
  injectedHeaders: Record<string, string>;
666
676
  applicationConfig: PushApplicationWithCommitConfig;
667
677
  }): Promise<RemoteCommitDto | undefined> {
668
- const serverURL = new URL(
669
- `${BASE_SERVER_PUBLIC_API_URL}/applications/${applicationId}/branches/${encodeURIComponent(
670
- branch
671
- )}/push`,
672
- superblocksBaseUrl
673
- );
674
- let serverResponse;
675
-
678
+ const handleHttpError = (status: number) => {
679
+ if (status === 405) {
680
+ throw new BranchNotCheckedOutError(`Branch ${branch} is not checked out`);
681
+ } else if (status === 409) {
682
+ throw new CommitAlreadyExistsError(
683
+ `Commit ${applicationConfig.commitId} already exists`
684
+ );
685
+ }
686
+ };
676
687
  try {
677
688
  const userMe = await fetchCurrentUser(
678
689
  cliVersion,
@@ -680,10 +691,18 @@ export async function pushApplication({
680
691
  superblocksBaseUrl
681
692
  );
682
693
  const organization = userMe.organizations[0];
683
- if (organization.agentType == AgentType.ONPREMISE && signingEnabled(userMe.flagBootstrap)) {
684
- const agentUrls = getAgentUrls(userMe.agents, organization.agentType);
694
+ if (
695
+ organization.agentType == AgentType.ONPREMISE &&
696
+ signingEnabled(userMe.flagBootstrap)
697
+ ) {
698
+ const profile = process.env.SUPERBLOCKS_PROFILE;
699
+ const agentUrl = await getAgentUrl(
700
+ userMe.agents,
701
+ organization.agentType,
702
+ profile
703
+ );
685
704
  const socket = await connectToISocketRPCServer({
686
- agentUrls,
705
+ agentUrl,
687
706
  superblocksBaseUrl,
688
707
  token,
689
708
  });
@@ -697,8 +716,21 @@ export async function pushApplication({
697
716
  page: applicationConfig.page,
698
717
  });
699
718
  socket.close();
719
+ handleHttpError(resp.responseMeta.status);
720
+ if (resp.responseMeta.status !== 200) {
721
+ // Get the raw error message from the server and throw it. The outer try-catch block will wrap it in a nicer error message
722
+ const message: string =
723
+ (resp?.responseMeta?.message as string) ?? JSON.stringify(resp?.data);
724
+ throw new Error(message);
725
+ }
700
726
  return resp.data;
701
727
  } else {
728
+ const serverURL = new URL(
729
+ `${BASE_SERVER_PUBLIC_API_URL}/applications/${applicationId}/branches/${encodeURIComponent(
730
+ branch
731
+ )}/push`,
732
+ superblocksBaseUrl
733
+ );
702
734
  const config: AxiosRequestConfig = {
703
735
  method: "post",
704
736
  url: serverURL.toString(),
@@ -709,29 +741,31 @@ export async function pushApplication({
709
741
  },
710
742
  data: applicationConfig,
711
743
  };
712
- serverResponse = await axios<ResponseWithMeta<RemoteCommitDto>>(config);
713
- }
714
- } catch (e) {
715
- if (axios.isAxiosError(e)) {
716
- const respCode =
717
- e.response?.data?.responseMeta?.status ?? e.response?.status;
718
- if (respCode === 405) {
719
- throw new BranchNotCheckedOutError(
720
- `Branch ${branch} is not checked out`
744
+ try {
745
+ const serverResponse = await axios<ResponseWithMeta<RemoteCommitDto>>(
746
+ config
721
747
  );
722
- } else if (respCode === 409) {
723
- throw new CommitAlreadyExistsError(
724
- `Commit ${applicationConfig.commitId} already exists`
748
+ return serverResponse?.data?.data;
749
+ } catch (e) {
750
+ if (!axios.isAxiosError(e)) {
751
+ throw e;
752
+ }
753
+ handleHttpError(
754
+ e.response?.data?.responseMeta?.status ?? e.response?.status
725
755
  );
756
+ const message =
757
+ (e.response?.data?.responseMeta?.message as string) ??
758
+ JSON.stringify(e.response?.data) ??
759
+ e.response?.statusText;
760
+ throw new Error(message);
726
761
  }
727
- const message: string =
728
- (e.response?.data?.responseMeta?.message as string) ??
729
- JSON.stringify(e.response?.data) ??
730
- e.response?.statusText;
731
-
732
- throw new Error(
733
- `Could not push application ${message ? "\n" + message : ""}`
734
- );
762
+ }
763
+ } catch (e) {
764
+ if (
765
+ e instanceof BranchNotCheckedOutError ||
766
+ e instanceof CommitAlreadyExistsError
767
+ ) {
768
+ throw e;
735
769
  }
736
770
  throw new Error(
737
771
  `Could not push application ${
@@ -739,8 +773,6 @@ export async function pushApplication({
739
773
  }`
740
774
  );
741
775
  }
742
-
743
- return serverResponse?.data?.data;
744
776
  }
745
777
 
746
778
  export async function pushApi({
@@ -760,14 +792,21 @@ export async function pushApi({
760
792
  branch: string;
761
793
  injectedHeaders: Record<string, string>;
762
794
  }): Promise<{ commitId: string } | undefined> {
795
+ const handleHttpError = (status: number) => {
796
+ if (status === 405) {
797
+ throw new BranchNotCheckedOutError(`Branch ${branch} is not checked out`);
798
+ } else if (status === 409) {
799
+ throw new CommitAlreadyExistsError(
800
+ `Commit ${apiConfig.commitId} already exists`
801
+ );
802
+ }
803
+ };
763
804
  const serverURL = new URL(
764
805
  `${BASE_SERVER_PUBLIC_API_URL}/apis/${apiId}/branches/${encodeURIComponent(
765
806
  branch
766
807
  )}/push`,
767
808
  superblocksBaseUrl
768
809
  );
769
- let serverResponse;
770
-
771
810
  try {
772
811
  const userMe = await fetchCurrentUser(
773
812
  cliVersion,
@@ -775,10 +814,13 @@ export async function pushApi({
775
814
  superblocksBaseUrl
776
815
  );
777
816
  const organization = userMe.organizations[0];
778
- if (organization.agentType == AgentType.ONPREMISE && signingEnabled(userMe.flagBootstrap)) {
779
- const agentUrls = getAgentUrls(userMe.agents, organization.agentType);
817
+ if (
818
+ organization.agentType == AgentType.ONPREMISE &&
819
+ signingEnabled(userMe.flagBootstrap)
820
+ ) {
821
+ const agentUrl = await getAgentUrl(userMe.agents, organization.agentType);
780
822
  const socket = await connectToISocketRPCServer({
781
- agentUrls,
823
+ agentUrl,
782
824
  superblocksBaseUrl,
783
825
  token,
784
826
  });
@@ -790,6 +832,13 @@ export async function pushApi({
790
832
  commitMessage: apiConfig.commitMessage,
791
833
  });
792
834
  socket.close();
835
+ handleHttpError(resp.responseMeta.status);
836
+ if (resp.responseMeta.status !== 200) {
837
+ // Get the raw error message from the server and throw it. The outer try-catch block will wrap it in a nicer error message
838
+ const message: string =
839
+ (resp?.responseMeta?.message as string) ?? JSON.stringify(resp?.data);
840
+ throw new Error(message);
841
+ }
793
842
  return resp.data;
794
843
  } else {
795
844
  const config: AxiosRequestConfig = {
@@ -802,27 +851,29 @@ export async function pushApi({
802
851
  },
803
852
  data: apiConfig,
804
853
  };
805
- serverResponse = await axios<ResponseWithMeta<{ commitId: string }>>(
806
- config
807
- );
854
+ try {
855
+ const serverResponse = await axios<
856
+ ResponseWithMeta<{ commitId: string }>
857
+ >(config);
858
+ return serverResponse?.data?.data;
859
+ } catch (e) {
860
+ if (!axios.isAxiosError(e)) {
861
+ throw e;
862
+ }
863
+ handleHttpError(e.response?.data?.responseMeta?.status);
864
+ const message =
865
+ (e.response?.data?.responseMeta?.message as string) ??
866
+ JSON.stringify(e.response?.data) ??
867
+ e.response?.statusText;
868
+ throw new Error(message);
869
+ }
808
870
  }
809
871
  } catch (e) {
810
- if (axios.isAxiosError(e)) {
811
- if (e.response?.data?.responseMeta?.status === 405) {
812
- throw new BranchNotCheckedOutError(
813
- `Branch ${branch} is not checked out`
814
- );
815
- } else if (e.response?.data?.responseMeta?.status === 409) {
816
- throw new CommitAlreadyExistsError(
817
- `Commit ${apiConfig.commitId} already exists`
818
- );
819
- }
820
- const message: string =
821
- (e.response?.data?.responseMeta?.message as string) ??
822
- JSON.stringify(e.response?.data) ??
823
- e.response?.statusText;
824
-
825
- throw new Error(`Could not push api ${message ? "\n" + message : ""}`);
872
+ if (
873
+ e instanceof BranchNotCheckedOutError ||
874
+ e instanceof CommitAlreadyExistsError
875
+ ) {
876
+ throw e;
826
877
  }
827
878
  throw new Error(
828
879
  `Could not push api ${
@@ -830,6 +881,4 @@ export async function pushApi({
830
881
  }`
831
882
  );
832
883
  }
833
-
834
- return serverResponse?.data?.data;
835
884
  }
@@ -49,6 +49,7 @@ type ResponseDto<T> = {
49
49
  export type ResponseMeta = {
50
50
  status: number;
51
51
  success: boolean;
52
+ message?: string;
52
53
  error?: APIResponseError;
53
54
  };
54
55
 
@@ -117,11 +118,11 @@ export interface ServerMethods {
117
118
  }
118
119
 
119
120
  export function createRequestHandlers({
120
- agentUrls,
121
+ agentUrl,
121
122
  token,
122
123
  }: {
123
124
  token: string;
124
- agentUrls: string[];
125
+ agentUrl?: string;
125
126
  }) {
126
127
  const requestHandlers: MethodHandlers<ClientMethods, ServerMethods, unknown> =
127
128
  {
@@ -135,8 +136,13 @@ export function createRequestHandlers({
135
136
  branchName: string;
136
137
  toSign: AppToSign;
137
138
  }) => {
139
+ if (!agentUrl) {
140
+ throw new Error(
141
+ "Agent url not specified. This shouldn't happen."
142
+ );
143
+ }
138
144
  const signature = await signResource({
139
- agentUrls,
145
+ agentUrl,
140
146
  token: token,
141
147
  branchName,
142
148
  resource: {
@@ -158,8 +164,13 @@ export function createRequestHandlers({
158
164
  }) => {
159
165
  const signatures: Signature[] = [];
160
166
  for (const { apiPb } of toSign) {
167
+ if (!agentUrl) {
168
+ throw new Error(
169
+ "Agent url not specified. This shouldn't happen."
170
+ );
171
+ }
161
172
  const signature = await signResource({
162
- agentUrls,
173
+ agentUrl,
163
174
  token: token,
164
175
  branchName,
165
176
  resource: { api: apiPb },
@@ -178,8 +189,13 @@ export function createRequestHandlers({
178
189
  toVerify: AppToVerify;
179
190
  }) => {
180
191
  try {
192
+ if (!agentUrl) {
193
+ throw new Error(
194
+ "Agent url not specified. This shouldn't happen."
195
+ );
196
+ }
181
197
  await verifyResources({
182
- agentUrls,
198
+ agentUrl,
183
199
  token,
184
200
  branchName,
185
201
  resources: [
@@ -207,8 +223,13 @@ export function createRequestHandlers({
207
223
  toVerify: ApiToVerify[];
208
224
  }) => {
209
225
  try {
226
+ if (!agentUrl) {
227
+ throw new Error(
228
+ "Agent url not specified. This shouldn't happen."
229
+ );
230
+ }
210
231
  await verifyResources({
211
- agentUrls,
232
+ agentUrl,
212
233
  token,
213
234
  branchName,
214
235
  resources: toVerify.map(({ apiPb }) => ({
@@ -10,15 +10,15 @@ export type StdISocketRPCClient = ISocketClient<ServerMethods>;
10
10
 
11
11
  export async function connectToISocketRPCServer({
12
12
  superblocksBaseUrl,
13
- agentUrls,
13
+ agentUrl,
14
14
  token,
15
15
  }: {
16
16
  superblocksBaseUrl: string;
17
- agentUrls: string[];
18
17
  token: string;
18
+ agentUrl?: string;
19
19
  }): Promise<StdISocketRPCClient> {
20
20
  const requestHandlers = createRequestHandlers({
21
- agentUrls,
21
+ agentUrl,
22
22
  token,
23
23
  });
24
24
  const authorization = `Bearer ${token}`;