@superblocksteam/sdk 1.8.2 → 1.9.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/dist/sdk.js CHANGED
@@ -14,7 +14,7 @@ class SuperblocksSdk {
14
14
  this.superblocksBaseUrl = superblocksBaseUrl;
15
15
  this.cliVersion = cliVersion;
16
16
  }
17
- async fetchApplication({ applicationId, branch, headers = {}, viewMode = "export-live", fetchSinglePageApplication = false, }) {
17
+ async fetchApplication({ applicationId, branch, headers = {}, viewMode = "export-live", skipSigningVerification = false, }) {
18
18
  return (0, client_1.fetchApplication)({
19
19
  cliVersion: this.cliVersion,
20
20
  applicationId,
@@ -22,8 +22,8 @@ class SuperblocksSdk {
22
22
  token: this.token,
23
23
  superblocksBaseUrl: this.superblocksBaseUrl,
24
24
  viewMode,
25
+ skipSigningVerification,
25
26
  injectedHeaders: headers,
26
- fetchSinglePageApplication,
27
27
  });
28
28
  }
29
29
  async fetchApplicationBranches(applicationId, headers = {}) {
@@ -35,7 +35,7 @@ class SuperblocksSdk {
35
35
  injectedHeaders: headers,
36
36
  });
37
37
  }
38
- async fetchApplicationWithComponents({ applicationId, branch, headers = {}, viewMode = "export-live", fetchSinglePageApplication = false, }) {
38
+ async fetchApplicationWithComponents({ applicationId, branch, headers = {}, viewMode = "export-live", commitId, skipSigningVerification = false, }) {
39
39
  return (0, client_1.fetchApplicationWithComponents)({
40
40
  cliVersion: this.cliVersion,
41
41
  applicationId,
@@ -43,15 +43,40 @@ class SuperblocksSdk {
43
43
  token: this.token,
44
44
  superblocksBaseUrl: this.superblocksBaseUrl,
45
45
  viewMode,
46
+ skipSigningVerification,
47
+ commitId,
46
48
  injectedHeaders: headers,
47
- fetchSinglePageApplication,
49
+ });
50
+ }
51
+ async fetchApplicationCommits({ applicationId, branch, headers = {}, limit, offset, }) {
52
+ return (0, client_1.fetchApplicationCommits)({
53
+ cliVersion: this.cliVersion,
54
+ applicationId,
55
+ branch,
56
+ token: this.token,
57
+ superblocksBaseUrl: this.superblocksBaseUrl,
58
+ injectedHeaders: headers,
59
+ limit,
60
+ offset,
61
+ });
62
+ }
63
+ async fetchApiCommits({ apiId, branch, headers = {}, limit, offset, }) {
64
+ return (0, client_1.fetchApiCommits)({
65
+ cliVersion: this.cliVersion,
66
+ applicationId: apiId,
67
+ branch,
68
+ token: this.token,
69
+ superblocksBaseUrl: this.superblocksBaseUrl,
70
+ injectedHeaders: headers,
71
+ limit,
72
+ offset,
48
73
  });
49
74
  }
50
75
  async fetchApplications(headers) {
51
76
  return (0, client_1.fetchApplications)(this.cliVersion, this.token, this.superblocksBaseUrl, headers);
52
77
  }
53
- async fetchApi(apiId, viewMode = "export-live", branch) {
54
- return (0, client_1.fetchApi)(this.cliVersion, apiId, this.token, this.superblocksBaseUrl, viewMode, branch);
78
+ async fetchApi({ apiId, branch, viewMode = "export-live", commitId, skipSigningVerification = false, }) {
79
+ return (0, client_1.fetchApi)(this.cliVersion, apiId, this.token, this.superblocksBaseUrl, viewMode, branch, commitId, skipSigningVerification);
55
80
  }
56
81
  async fetchApis() {
57
82
  return (0, client_1.fetchApis)(this.cliVersion, this.token, this.superblocksBaseUrl);
@@ -76,7 +101,7 @@ class SuperblocksSdk {
76
101
  async fetchCurrentUser() {
77
102
  return (0, client_1.fetchCurrentUser)(this.cliVersion, this.token, this.superblocksBaseUrl);
78
103
  }
79
- async pushApplication({ applicationId, applicationConfig, branch, headers = {}, multiPage = false, }) {
104
+ async pushApplication({ applicationId, applicationConfig, branch, headers = {}, }) {
80
105
  return (0, client_1.pushApplication)({
81
106
  cliVersion: this.cliVersion,
82
107
  applicationId,
@@ -85,7 +110,6 @@ class SuperblocksSdk {
85
110
  branch,
86
111
  injectedHeaders: headers,
87
112
  applicationConfig,
88
- multiPage,
89
113
  });
90
114
  }
91
115
  async pushApi({ apiId, apiConfig, branch, headers = {}, }) {
@@ -1,5 +1,5 @@
1
1
  import { LocalGitRepoState } from "@superblocksteam/util";
2
- import { ApiToSign, ApiToVerify, AppToSign, AppToVerify, MethodHandlers, RemoteCommitDto, Signature } from "../types";
2
+ import { ApiToSign, ApiToVerify, AppToSign, AppToVerify, MethodHandlers, RemoteCommitDto, Signature, ViewMode } from "../types";
3
3
  type MethodSchema<Params, Response> = (params: Params) => Promise<Response>;
4
4
  export interface ClientMethods {
5
5
  v1: {
@@ -93,11 +93,20 @@ export interface ServerMethods {
93
93
  pushCommit: ServerMethodSchema<{
94
94
  apiId: string;
95
95
  branchName: string;
96
- commitId: string;
97
- commitMessage: string;
96
+ commitId?: string;
97
+ commitMessage?: string;
98
98
  apiPb: Record<string, unknown>;
99
99
  gitState: LocalGitRepoState;
100
- }, RemoteCommitDto>;
100
+ skipCommit: boolean;
101
+ }, RemoteCommitDto | {
102
+ updated: Date;
103
+ }>;
104
+ get: ServerMethodSchema<{
105
+ apiId: string;
106
+ branchName?: string;
107
+ viewMode: ViewMode;
108
+ commitId?: string;
109
+ }, any>;
101
110
  };
102
111
  };
103
112
  };
@@ -107,13 +116,22 @@ export interface ServerMethods {
107
116
  pushCommit: ServerMethodSchema<{
108
117
  applicationId: string;
109
118
  branchName: string;
110
- commitId: string;
111
- commitMessage: string;
119
+ commitId?: string;
120
+ commitMessage?: string;
112
121
  application: Record<string, unknown>;
113
122
  pages: Record<string, unknown>[];
114
123
  apis: Record<string, unknown>[];
115
124
  gitState: LocalGitRepoState;
116
- }, RemoteCommitDto>;
125
+ skipCommit: boolean;
126
+ }, RemoteCommitDto | {
127
+ updated: Date;
128
+ }>;
129
+ get: ServerMethodSchema<{
130
+ applicationId: string;
131
+ viewMode: ViewMode;
132
+ branchName?: string;
133
+ commitId?: string;
134
+ }, any>;
117
135
  };
118
136
  };
119
137
  };
@@ -1,26 +1,18 @@
1
1
  import WebSocket from "ws";
2
+ import { GenericMiddleware, ISocketClient, MethodHandlers, RequestContextBase, SocketTimeouts } from "../types";
2
3
  import { ServerMethods } from "./handlers";
4
+ import { ISocket } from "./socket";
3
5
  export type StdISocketRPCClient = ISocketClient<ServerMethods>;
4
6
  export declare function connectToISocketRPCServer({ superblocksBaseUrl, agentUrl, token, }: {
5
7
  superblocksBaseUrl: string;
6
8
  token: string;
7
9
  agentUrl?: string;
8
10
  }): Promise<StdISocketRPCClient>;
9
- export declare function connectISocket<CallableMethods, ImplementedMethods, RequestContext = never>(wsUrl: string, authorization: string | undefined, requestHandlers: MethodHandlers<ImplementedMethods, CallableMethods, RequestContext>): Promise<ISocketClient<CallableMethods>>;
11
+ export declare class ISocketWithClientAuth<ImplementedMethods, CallableMethods, RequestContext extends RequestContextBase> extends ISocket<ImplementedMethods, CallableMethods, RequestContext> {
12
+ private readonly authorization?;
13
+ private hasSentAuth;
14
+ constructor(ws: WebSocket, authorization: string | undefined, requestHandlers: MethodHandlers<ImplementedMethods, CallableMethods, RequestContext>, globalMiddlewares: GenericMiddleware<CallableMethods, RequestContext>[], timeouts?: SocketTimeouts);
15
+ request<Params, Result>(method: string, params: Params): Promise<Result>;
16
+ }
17
+ export declare function connectISocket<CallableMethods, ImplementedMethods, RequestContext extends RequestContextBase = RequestContextBase>(wsUrl: string, authorization: string | undefined, requestHandlers: MethodHandlers<ImplementedMethods, CallableMethods, RequestContext>, globalMiddlewares: GenericMiddleware<CallableMethods, RequestContext>[], timeouts?: SocketTimeouts): Promise<ISocketClient<CallableMethods>>;
10
18
  export declare function connectWebSocket(wsUrl: string): Promise<WebSocket>;
11
- type MethodHandler<Params, Result, PeerMethods, RequestContext> = (params: Params, peer: ISocketClient<PeerMethods>, ctx: RequestContext) => Promise<Result>;
12
- type MiddlewareHandler<Params, PeerMethods, RequestContext> = (params: Params, peerAuthorization: string | undefined, peer: ISocketClient<PeerMethods>, ctx: RequestContext) => Promise<void>;
13
- type MethodHandlers<Methods, PeerMethods, RequestContext> = {
14
- [Key in keyof Methods]: Methods[Key] extends (params: infer Params) => Promise<infer Result> ? [
15
- ...middlewareHandlers: MiddlewareHandler<Params, PeerMethods, RequestContext>[],
16
- handler: MethodHandler<Params, Result, PeerMethods, RequestContext>
17
- ] : Methods[Key] extends Record<string, unknown> ? MethodHandlers<Methods[Key], PeerMethods, RequestContext> : never;
18
- };
19
- type ISocketClientMethodCall<Methods> = {
20
- [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;
21
- };
22
- type ISocketClient<Methods> = {
23
- close: () => void;
24
- call: ISocketClientMethodCall<Methods>;
25
- };
26
- export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.connectWebSocket = exports.connectISocket = exports.connectToISocketRPCServer = void 0;
3
+ exports.connectWebSocket = exports.connectISocket = exports.ISocketWithClientAuth = exports.connectToISocketRPCServer = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const ws_1 = tslib_1.__importDefault(require("ws"));
6
6
  const handlers_1 = require("./handlers");
@@ -24,15 +24,18 @@ async function connectToISocketRPCServer({ superblocksBaseUrl, agentUrl, token,
24
24
  else if (wsUrl.hostname === "localhost") {
25
25
  wsUrl.hostname = "127.0.0.1";
26
26
  }
27
- return await connectISocket(wsUrl.href, authorization, requestHandlers);
27
+ return await connectISocket(wsUrl.href, authorization, requestHandlers, [], {
28
+ connectionTimeoutInSeconds: 6 * 60,
29
+ noResponseTimeoutInSeconds: 5 * 60, // 5 minutes
30
+ });
28
31
  }
29
32
  exports.connectToISocketRPCServer = connectToISocketRPCServer;
30
33
  // a subclass of ISocket that sends an auth token on the first request
31
34
  // this is useful for client-side sockets that need to authenticate
32
35
  // TODO(george): if we start using this for long-lived connections, we should add a way to refresh the token
33
36
  class ISocketWithClientAuth extends socket_1.ISocket {
34
- constructor(ws, authorization, requestHandlers) {
35
- super(ws, requestHandlers);
37
+ constructor(ws, authorization, requestHandlers, globalMiddlewares, timeouts) {
38
+ super(ws, requestHandlers, globalMiddlewares, timeouts);
36
39
  this.hasSentAuth = false;
37
40
  this.authorization = authorization;
38
41
  }
@@ -45,9 +48,10 @@ class ISocketWithClientAuth extends socket_1.ISocket {
45
48
  return result;
46
49
  }
47
50
  }
48
- async function connectISocket(wsUrl, authorization, requestHandlers) {
51
+ exports.ISocketWithClientAuth = ISocketWithClientAuth;
52
+ async function connectISocket(wsUrl, authorization, requestHandlers, globalMiddlewares, timeouts) {
49
53
  const ws = await connectWebSocket(wsUrl);
50
- const isocket = new ISocketWithClientAuth(ws, authorization, requestHandlers);
54
+ const isocket = new ISocketWithClientAuth(ws, authorization, requestHandlers, globalMiddlewares, timeouts);
51
55
  return (0, socket_1.createISocketClient)(isocket);
52
56
  }
53
57
  exports.connectISocket = connectISocket;
@@ -1,16 +1,60 @@
1
1
  import WebSocket from "ws";
2
- import { ISocketClient, MethodHandlers } from "../types";
3
- export declare class ISocket<ImplementedMethods, CallableMethods, RequestContext> {
2
+ import { ISocketClient, MethodHandler, MethodHandlers, RequestContextBase, SocketTimeouts, GenericMiddleware } from "../types";
3
+ interface SocketRequest<Payload = unknown> {
4
+ method: string;
5
+ payload: Payload;
6
+ id: number;
7
+ setAuthorization?: string;
8
+ }
9
+ interface SocketResponse<Payload = unknown> {
10
+ id: number;
11
+ payload: Payload;
12
+ error: SocketError | null;
13
+ }
14
+ export interface SocketMessage<RequestPayload = unknown, ResponsePayload = unknown> {
15
+ request?: SocketRequest<RequestPayload>;
16
+ response?: SocketResponse<ResponsePayload>;
17
+ }
18
+ export interface SocketError {
19
+ message: string;
20
+ code: number;
21
+ }
22
+ /**
23
+ * ISocket is a class that wraps a WebSocket connection and provides a simple interface for sending and receiving messages.
24
+ * ISocket is initialized by both server and client and request/response is called symmetrically.
25
+ *
26
+ * ISocket handles has two timeout actions:
27
+ * 1. Connection timeout: If the connection is not closed after a certain time, the connection is closed.
28
+ * - This is useful to prevent a connection from being open indefinitely. This is mainly used in the server side since
29
+ * the client side manages connection lifecycle manually.
30
+ * 2. No response timeout: If the response is not received after a certain time, the request is timed out.
31
+ * - This is mainly used by CLI to handle the case where the server is not responding.
32
+ *
33
+ * It is expected that timeouts should be relatively sorted in the order of connection timeout > request timeout > no response timeout.
34
+ */
35
+ export declare class ISocket<ImplementedMethods, CallableMethods, RequestContext extends RequestContextBase> {
4
36
  private readonly ws;
5
37
  private readonly requestHandlers;
38
+ private readonly globalMiddlewares;
6
39
  private readonly responseHandler;
7
40
  private peerAuthorization?;
8
- private nxtRequestId;
9
- constructor(ws: WebSocket, requestHandlers: MethodHandlers<ImplementedMethods, CallableMethods, RequestContext>);
10
- private handleEvent;
41
+ protected nxtRequestId: number;
42
+ private connectionTimeout?;
43
+ private logger;
44
+ private timeouts?;
45
+ constructor(ws: WebSocket, requestHandlers: MethodHandlers<ImplementedMethods, CallableMethods, RequestContext>, globalMiddlewares: GenericMiddleware<CallableMethods, RequestContext>[], timeouts?: SocketTimeouts, logger?: {
46
+ error: (message?: string) => void;
47
+ });
48
+ protected handleMessage(message: SocketMessage): Promise<void>;
49
+ protected callHandler<Params, Result, CallableMethods, RequestContext extends RequestContextBase>(handler: MethodHandler<Params, Result, CallableMethods, RequestContext>, params: Params, ctx: RequestContext, client: ISocketClient<CallableMethods>, next: () => Promise<Result>): Promise<Result>;
11
50
  request<Params, Result>(method: string, params: Params, authorization?: string): Promise<Result>;
12
- private respond;
13
- private respondError;
51
+ protected respond<Result>(requestId: number, result: Result): void;
52
+ protected respondError(requestId: number, error: SocketError): void;
53
+ private resetConnectionTimeout;
54
+ private handleConnectionTimeout;
55
+ private resetNoResponseTimeout;
56
+ private handleNoResponseTimeout;
14
57
  close(): void;
15
58
  }
16
- export declare function createISocketClient<CallableMethods, ImplementedMethods, RequestContext>(socket: ISocket<ImplementedMethods, CallableMethods, RequestContext>): ISocketClient<CallableMethods>;
59
+ export declare function createISocketClient<CallableMethods, ImplementedMethods, RequestContext extends RequestContextBase>(socket: ISocket<ImplementedMethods, CallableMethods, RequestContext>): ISocketClient<CallableMethods>;
60
+ export {};
@@ -1,72 +1,114 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createISocketClient = exports.ISocket = void 0;
4
+ const types_1 = require("../types");
5
+ /**
6
+ * ISocket is a class that wraps a WebSocket connection and provides a simple interface for sending and receiving messages.
7
+ * ISocket is initialized by both server and client and request/response is called symmetrically.
8
+ *
9
+ * ISocket handles has two timeout actions:
10
+ * 1. Connection timeout: If the connection is not closed after a certain time, the connection is closed.
11
+ * - This is useful to prevent a connection from being open indefinitely. This is mainly used in the server side since
12
+ * the client side manages connection lifecycle manually.
13
+ * 2. No response timeout: If the response is not received after a certain time, the request is timed out.
14
+ * - This is mainly used by CLI to handle the case where the server is not responding.
15
+ *
16
+ * It is expected that timeouts should be relatively sorted in the order of connection timeout > request timeout > no response timeout.
17
+ */
4
18
  class ISocket {
5
- constructor(ws, requestHandlers) {
6
- this.responseHandler = {};
19
+ constructor(ws, requestHandlers, globalMiddlewares, timeouts, logger) {
20
+ this.responseHandler = new Map();
7
21
  this.ws = ws;
8
22
  this.requestHandlers = requestHandlers;
23
+ this.globalMiddlewares = globalMiddlewares;
9
24
  this.nxtRequestId = 0;
10
- this.ws.addEventListener("message", (event) => {
25
+ this.logger = logger ?? { error: console.error };
26
+ this.timeouts = timeouts;
27
+ // reset connection timeout in each message received. It means connection still active
28
+ this.resetConnectionTimeout();
29
+ this.ws.addEventListener("message",
30
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
31
+ async (event) => {
11
32
  const eventData = JSON.parse(event.data.toString());
12
- void this.handleEvent(eventData);
33
+ return this.handleMessage(eventData);
13
34
  });
14
35
  }
15
- async handleEvent(eventData) {
16
- if (eventData.request) {
36
+ async handleMessage(message) {
37
+ this.resetConnectionTimeout();
38
+ if (message.request) {
17
39
  // Split the method string into parts
18
- const parts = eventData.request.method.split(".");
40
+ const parts = message.request.method.split(".");
19
41
  let handlers = this.requestHandlers;
20
42
  for (const part of parts) {
21
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
22
- // @ts-ignore
23
43
  handlers = handlers[part];
24
44
  if (!handlers) {
25
- return this.respondError(eventData.request.id, {
45
+ return this.respondError(message.request.id, {
26
46
  code: 2,
27
- message: `unknown method ${eventData.request.method}`,
47
+ message: `unknown method ${message.request.method}`,
28
48
  });
29
49
  }
30
50
  }
31
51
  if (!Array.isArray(handlers)) {
32
- return this.respondError(eventData.request.id, {
52
+ return this.respondError(message.request.id, {
33
53
  code: 2,
34
54
  message: "unknown method",
35
55
  });
36
56
  }
37
- if (eventData.request.setAuthorization) {
38
- this.peerAuthorization = eventData.request.setAuthorization;
57
+ handlers = [...this.globalMiddlewares, ...handlers];
58
+ if (message.request.setAuthorization) {
59
+ this.peerAuthorization = message.request.setAuthorization;
39
60
  }
40
- const middlewareHandlers = handlers.slice(0, -1);
41
- const handler = handlers[handlers.length - 1];
42
- const reqCtx = {};
43
- let response;
44
- // TODO(george): maybe we should not create a new client for each request
61
+ const reqCtx = {
62
+ peerAuthorization: this.peerAuthorization,
63
+ method: message.request.method,
64
+ requestId: message.request.id,
65
+ };
45
66
  const client = createISocketClient(this);
67
+ const payload = message.request.payload;
68
+ let alreadyResponded = false;
69
+ const generateNextFn = (idx) => {
70
+ let wasCalled = false;
71
+ return async () => {
72
+ if (alreadyResponded) {
73
+ throw new types_1.SocketErrorException(4, "next() was called after the response was sent");
74
+ }
75
+ const handler = handlers[idx];
76
+ if (!handler) {
77
+ throw new types_1.SocketErrorException(5, "cannot call past the last handler in the chain");
78
+ }
79
+ if (wasCalled) {
80
+ throw new types_1.SocketErrorException(6, "next() was called multiple times");
81
+ }
82
+ wasCalled = true;
83
+ return this.callHandler(handler, payload, reqCtx, client, generateNextFn(idx + 1));
84
+ };
85
+ };
86
+ let response;
46
87
  try {
47
- for (const middlewareHandler of middlewareHandlers) {
48
- await middlewareHandler(eventData.request.payload, this.peerAuthorization, client, reqCtx);
49
- }
50
- response = await handler(eventData.request.payload, client, reqCtx);
88
+ // call the first handler in the chain
89
+ response = await generateNextFn(0)();
51
90
  }
52
91
  catch (error) {
53
- return this.respondError(eventData.request.id, {
54
- code: 3,
55
- message: error.toString(),
56
- });
92
+ const socketError = error instanceof types_1.SocketErrorException
93
+ ? { code: error.code, message: error.message }
94
+ : { code: 3, message: error.toString() };
95
+ return this.respondError(message.request.id, socketError);
57
96
  }
58
- this.respond(eventData.request.id, response);
97
+ this.respond(message.request.id, response);
98
+ alreadyResponded = true;
59
99
  }
60
- else if (eventData.response && eventData.response.id) {
61
- if (!this.responseHandler[eventData.response.id]) {
100
+ else if (message.response && message.response.id) {
101
+ const responseHandler = this.responseHandler.get(message.response.id);
102
+ if (!responseHandler) {
62
103
  return;
63
104
  }
64
- if (eventData.response.error) {
65
- this.responseHandler[eventData.response.id].reject(eventData.response.error);
105
+ if (message.response.error) {
106
+ responseHandler.reject(message.response.error);
66
107
  }
67
108
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
- this.responseHandler[eventData.response.id].resolve(eventData.response.payload);
69
- delete this.responseHandler[eventData.response.id];
109
+ responseHandler.resolve(message.response.payload);
110
+ clearTimeout(responseHandler.timeout);
111
+ this.responseHandler.delete(message.response.id);
70
112
  }
71
113
  else {
72
114
  return this.respondError(-1, {
@@ -75,13 +117,16 @@ class ISocket {
75
117
  });
76
118
  }
77
119
  }
120
+ async callHandler(handler, params, ctx, client, next) {
121
+ return handler(params, ctx, client, next);
122
+ }
78
123
  request(method, params, authorization) {
79
124
  return new Promise((resolve, reject) => {
80
125
  const requestId = ++this.nxtRequestId;
81
- this.responseHandler[requestId] = {
126
+ this.responseHandler.set(requestId, {
82
127
  resolve: (result) => resolve(result),
83
128
  reject: (error) => reject(error),
84
- };
129
+ });
85
130
  const toSend = {
86
131
  request: {
87
132
  method,
@@ -91,6 +136,7 @@ class ISocket {
91
136
  },
92
137
  };
93
138
  this.ws.send(JSON.stringify(toSend));
139
+ this.resetNoResponseTimeout(requestId);
94
140
  });
95
141
  }
96
142
  respond(requestId, result) {
@@ -113,7 +159,52 @@ class ISocket {
113
159
  };
114
160
  return this.ws.send(JSON.stringify(toSend));
115
161
  }
162
+ resetConnectionTimeout() {
163
+ if (!this.timeouts?.connectionTimeoutInSeconds) {
164
+ return;
165
+ }
166
+ if (this.connectionTimeout) {
167
+ clearTimeout(this.connectionTimeout);
168
+ }
169
+ // Set a new timeout for the next message
170
+ this.connectionTimeout = setTimeout(this.handleConnectionTimeout(), this.timeouts?.connectionTimeoutInSeconds * 1000);
171
+ }
172
+ handleConnectionTimeout() {
173
+ return () => {
174
+ this.logger.error(`Connection timed out after ${this.timeouts?.connectionTimeoutInSeconds} seconds`);
175
+ this.close();
176
+ };
177
+ }
178
+ resetNoResponseTimeout(requestId) {
179
+ if (!this.timeouts?.noResponseTimeoutInSeconds) {
180
+ return;
181
+ }
182
+ const responseHandler = this.responseHandler.get(requestId);
183
+ if (!responseHandler) {
184
+ return;
185
+ }
186
+ const noResponseTimeout = responseHandler.timeout;
187
+ const reject = responseHandler.reject;
188
+ if (responseHandler.timeout) {
189
+ clearTimeout(noResponseTimeout);
190
+ }
191
+ // Set a new timeout for the next message
192
+ responseHandler.timeout = setTimeout(this.handleNoResponseTimeout(reject), this.timeouts?.noResponseTimeoutInSeconds * 1000);
193
+ }
194
+ handleNoResponseTimeout(reject) {
195
+ return () => {
196
+ const message = `Request timed out after ${this.timeouts?.noResponseTimeoutInSeconds} seconds`;
197
+ this.logger.error(message);
198
+ reject({ code: 7, message });
199
+ };
200
+ }
116
201
  close() {
202
+ clearTimeout(this.connectionTimeout);
203
+ this.responseHandler.forEach((handler, key) => {
204
+ clearTimeout(handler.timeout);
205
+ this.logger.error(`Rejecting pending requestId ${key} due to connection close`);
206
+ handler.reject({ code: 8, message: "Connection closed" });
207
+ });
117
208
  this.ws.close();
118
209
  }
119
210
  }
@@ -152,7 +243,7 @@ path) {
152
243
  function createISocketClient(socket) {
153
244
  return {
154
245
  close: () => socket.close(),
155
- // eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment
246
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
156
247
  call: createIsocketProxy(socket, undefined),
157
248
  };
158
249
  }
@@ -6,7 +6,6 @@ export interface UserMeDto {
6
6
  }
7
7
  export interface FlagBootstrap {
8
8
  "ui.enable-resource-signing"?: boolean;
9
- "ui.multi-page.enabled"?: boolean;
10
9
  }
11
10
  export type User = {
12
11
  id: string;
@@ -123,3 +122,4 @@ export interface RemoteCommitDto {
123
122
  branchName: string;
124
123
  repositoryId: string;
125
124
  }
125
+ export type ViewMode = "export-deployed" | "export-latest" | "export-live" | "export-commit";
@@ -1,10 +1,13 @@
1
- export type MethodHandler<Params, Result, PeerMethods, RequestContext> = (params: Params, peer: ISocketClient<PeerMethods>, ctx: RequestContext) => Promise<Result>;
2
- export type MiddlewareHandler<Params, PeerMethods, RequestContext> = (params: Params, peerAuthorization: string | undefined, peer: ISocketClient<PeerMethods>, ctx: RequestContext) => Promise<void>;
1
+ export interface RequestContextBase {
2
+ peerAuthorization?: string;
3
+ method: string;
4
+ requestId: number;
5
+ }
6
+ export type MethodHandler<Params, Result, PeerMethods, RequestContext> = (params: Params, ctx: RequestContext, peer: ISocketClient<PeerMethods>, next: () => Promise<Result>) => Promise<Result>;
7
+ export type GenericMiddleware<PeerMethods, RequestContext> = MethodHandler<any, any, PeerMethods, RequestContext>;
8
+ export type NonEmptyArray<T> = [...T[], T];
3
9
  export type MethodHandlers<Methods, PeerMethods, RequestContext> = {
4
- [Key in keyof Methods]: Methods[Key] extends (params: infer Params) => Promise<infer Result> ? [
5
- ...middlewareHandlers: MiddlewareHandler<Params, PeerMethods, RequestContext>[],
6
- handler: MethodHandler<Params, Result, PeerMethods, RequestContext>
7
- ] : Methods[Key] extends Record<string, unknown> ? MethodHandlers<Methods[Key], PeerMethods, RequestContext> : never;
10
+ [Key in keyof Methods]: Methods[Key] extends (params: infer Params) => Promise<infer Result> ? NonEmptyArray<MethodHandler<Params, Result, PeerMethods, RequestContext>> : Methods[Key] extends Record<string, unknown> ? MethodHandlers<Methods[Key], PeerMethods, RequestContext> : never;
8
11
  };
9
12
  type ISocketClientMethodCall<Methods> = {
10
13
  [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;
@@ -14,4 +17,14 @@ export type ISocketClient<Methods> = {
14
17
  call: ISocketClientMethodCall<Methods>;
15
18
  };
16
19
  export type MethodSchema<Params, Response> = (params: Params) => Promise<Response>;
20
+ /** The exception type can be thrown to cause the default error handler to write a raw error response to the socket */
21
+ export declare class SocketErrorException extends Error {
22
+ readonly code: number;
23
+ readonly message: string;
24
+ constructor(code: number, message: string);
25
+ }
26
+ export type SocketTimeouts = {
27
+ noResponseTimeoutInSeconds?: number;
28
+ connectionTimeoutInSeconds?: number;
29
+ };
17
30
  export {};
@@ -1,2 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SocketErrorException = void 0;
4
+ /** The exception type can be thrown to cause the default error handler to write a raw error response to the socket */
5
+ class SocketErrorException extends Error {
6
+ constructor(code, message) {
7
+ super(message);
8
+ this.code = code;
9
+ this.message = message;
10
+ }
11
+ }
12
+ exports.SocketErrorException = SocketErrorException;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superblocksteam/sdk",
3
- "version": "1.8.2",
3
+ "version": "1.9.1",
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.8.2",
34
+ "@superblocksteam/util": "1.9.1",
35
35
  "axios": "^1.3.5",
36
36
  "ws": "^8.17.0"
37
37
  },