@granular-software/sdk 0.3.2 → 0.3.4
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/adapters/anthropic.d.mts +1 -1
- package/dist/adapters/anthropic.d.ts +1 -1
- package/dist/adapters/langchain.d.mts +1 -1
- package/dist/adapters/langchain.d.ts +1 -1
- package/dist/adapters/mastra.d.mts +1 -1
- package/dist/adapters/mastra.d.ts +1 -1
- package/dist/adapters/openai.d.mts +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/cli/index.js +443 -22
- package/dist/index.d.mts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +110 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +110 -16
- package/dist/index.mjs.map +1 -1
- package/dist/{types-CnX4jXYQ.d.mts → types-D5B8WlF4.d.mts} +27 -1
- package/dist/{types-CnX4jXYQ.d.ts → types-D5B8WlF4.d.ts} +27 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3966,6 +3966,10 @@ var WSClient = class {
|
|
|
3966
3966
|
*/
|
|
3967
3967
|
async connect() {
|
|
3968
3968
|
this.isExplicitlyDisconnected = false;
|
|
3969
|
+
if (this.reconnectTimer) {
|
|
3970
|
+
clearTimeout(this.reconnectTimer);
|
|
3971
|
+
this.reconnectTimer = null;
|
|
3972
|
+
}
|
|
3969
3973
|
let WebSocketClass = this.options.WebSocketCtor || GlobalWebSocket;
|
|
3970
3974
|
if (!WebSocketClass) {
|
|
3971
3975
|
try {
|
|
@@ -3987,6 +3991,10 @@ var WSClient = class {
|
|
|
3987
3991
|
const socket = this.ws;
|
|
3988
3992
|
if (typeof socket.on === "function") {
|
|
3989
3993
|
socket.on("open", () => {
|
|
3994
|
+
if (this.reconnectTimer) {
|
|
3995
|
+
clearTimeout(this.reconnectTimer);
|
|
3996
|
+
this.reconnectTimer = null;
|
|
3997
|
+
}
|
|
3990
3998
|
this.emit("open", {});
|
|
3991
3999
|
resolve();
|
|
3992
4000
|
});
|
|
@@ -4004,12 +4012,20 @@ var WSClient = class {
|
|
|
4004
4012
|
reject(error);
|
|
4005
4013
|
}
|
|
4006
4014
|
});
|
|
4007
|
-
socket.on("close", () => {
|
|
4008
|
-
this.
|
|
4009
|
-
|
|
4015
|
+
socket.on("close", (code, reason) => {
|
|
4016
|
+
this.handleDisconnect({
|
|
4017
|
+
code,
|
|
4018
|
+
reason: this.normalizeReason(reason),
|
|
4019
|
+
// ws does not provide wasClean on Node-style close callback
|
|
4020
|
+
wasClean: code === 1e3
|
|
4021
|
+
});
|
|
4010
4022
|
});
|
|
4011
4023
|
} else {
|
|
4012
4024
|
this.ws.onopen = () => {
|
|
4025
|
+
if (this.reconnectTimer) {
|
|
4026
|
+
clearTimeout(this.reconnectTimer);
|
|
4027
|
+
this.reconnectTimer = null;
|
|
4028
|
+
}
|
|
4013
4029
|
this.emit("open", {});
|
|
4014
4030
|
resolve();
|
|
4015
4031
|
};
|
|
@@ -4030,9 +4046,12 @@ var WSClient = class {
|
|
|
4030
4046
|
reject(error);
|
|
4031
4047
|
}
|
|
4032
4048
|
};
|
|
4033
|
-
this.ws.onclose = () => {
|
|
4034
|
-
this.
|
|
4035
|
-
|
|
4049
|
+
this.ws.onclose = (event) => {
|
|
4050
|
+
this.handleDisconnect({
|
|
4051
|
+
code: event.code,
|
|
4052
|
+
reason: event.reason,
|
|
4053
|
+
wasClean: event.wasClean
|
|
4054
|
+
});
|
|
4036
4055
|
};
|
|
4037
4056
|
}
|
|
4038
4057
|
} catch (error) {
|
|
@@ -4040,13 +4059,80 @@ var WSClient = class {
|
|
|
4040
4059
|
}
|
|
4041
4060
|
});
|
|
4042
4061
|
}
|
|
4043
|
-
|
|
4062
|
+
normalizeReason(reason) {
|
|
4063
|
+
if (reason === null || reason === void 0) return void 0;
|
|
4064
|
+
if (typeof reason === "string") return reason;
|
|
4065
|
+
if (typeof reason === "object" && reason && "toString" in reason) {
|
|
4066
|
+
try {
|
|
4067
|
+
const text = String(reason.toString());
|
|
4068
|
+
return text || void 0;
|
|
4069
|
+
} catch {
|
|
4070
|
+
return void 0;
|
|
4071
|
+
}
|
|
4072
|
+
}
|
|
4073
|
+
return void 0;
|
|
4074
|
+
}
|
|
4075
|
+
rejectPending(error) {
|
|
4076
|
+
this.messageQueue.forEach((pending) => pending.reject(error));
|
|
4077
|
+
this.messageQueue = [];
|
|
4078
|
+
}
|
|
4079
|
+
buildDisconnectError(info) {
|
|
4080
|
+
const details = [
|
|
4081
|
+
info.code !== void 0 ? `code=${info.code}` : void 0,
|
|
4082
|
+
info.reason ? `reason=${info.reason}` : void 0
|
|
4083
|
+
].filter(Boolean).join(", ");
|
|
4084
|
+
const suffix = details ? ` (${details})` : "";
|
|
4085
|
+
return new Error(`WebSocket disconnected${suffix}`);
|
|
4086
|
+
}
|
|
4087
|
+
handleDisconnect(close = {}) {
|
|
4088
|
+
const reconnectDelayMs = 3e3;
|
|
4089
|
+
const unexpected = !this.isExplicitlyDisconnected;
|
|
4090
|
+
const info = {
|
|
4091
|
+
code: close.code,
|
|
4092
|
+
reason: close.reason,
|
|
4093
|
+
wasClean: close.wasClean,
|
|
4094
|
+
unexpected,
|
|
4095
|
+
timestamp: Date.now(),
|
|
4096
|
+
reconnectScheduled: false
|
|
4097
|
+
};
|
|
4044
4098
|
this.ws = null;
|
|
4045
|
-
|
|
4099
|
+
this.emit("close", info);
|
|
4100
|
+
if (this.reconnectTimer) {
|
|
4101
|
+
clearTimeout(this.reconnectTimer);
|
|
4102
|
+
this.reconnectTimer = null;
|
|
4103
|
+
}
|
|
4104
|
+
if (unexpected) {
|
|
4105
|
+
const disconnectError = this.buildDisconnectError(info);
|
|
4106
|
+
this.rejectPending(disconnectError);
|
|
4107
|
+
this.emit("disconnect", info);
|
|
4108
|
+
info.reconnectScheduled = true;
|
|
4109
|
+
info.reconnectDelayMs = reconnectDelayMs;
|
|
4110
|
+
if (this.options.onUnexpectedClose) {
|
|
4111
|
+
try {
|
|
4112
|
+
this.options.onUnexpectedClose(info);
|
|
4113
|
+
} catch (callbackError) {
|
|
4114
|
+
console.error("[Granular] onUnexpectedClose callback failed:", callbackError);
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4046
4117
|
this.reconnectTimer = setTimeout(() => {
|
|
4047
4118
|
console.log("[Granular] Attempting reconnect...");
|
|
4048
|
-
this.connect().catch((
|
|
4049
|
-
|
|
4119
|
+
this.connect().catch((error) => {
|
|
4120
|
+
console.error("[Granular] Reconnect failed:", error);
|
|
4121
|
+
const reconnectInfo = {
|
|
4122
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4123
|
+
sessionId: this.sessionId,
|
|
4124
|
+
timestamp: Date.now()
|
|
4125
|
+
};
|
|
4126
|
+
this.emit("reconnect_error", reconnectInfo);
|
|
4127
|
+
if (this.options.onReconnectError) {
|
|
4128
|
+
try {
|
|
4129
|
+
this.options.onReconnectError(reconnectInfo);
|
|
4130
|
+
} catch (callbackError) {
|
|
4131
|
+
console.error("[Granular] onReconnectError callback failed:", callbackError);
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
});
|
|
4135
|
+
}, reconnectDelayMs);
|
|
4050
4136
|
}
|
|
4051
4137
|
}
|
|
4052
4138
|
handleMessage(message) {
|
|
@@ -4266,13 +4352,15 @@ var WSClient = class {
|
|
|
4266
4352
|
*/
|
|
4267
4353
|
disconnect() {
|
|
4268
4354
|
this.isExplicitlyDisconnected = true;
|
|
4269
|
-
if (this.reconnectTimer)
|
|
4355
|
+
if (this.reconnectTimer) {
|
|
4356
|
+
clearTimeout(this.reconnectTimer);
|
|
4357
|
+
this.reconnectTimer = null;
|
|
4358
|
+
}
|
|
4270
4359
|
if (this.ws) {
|
|
4271
|
-
this.ws.close();
|
|
4360
|
+
this.ws.close(1e3, "Client disconnect");
|
|
4272
4361
|
this.ws = null;
|
|
4273
4362
|
}
|
|
4274
|
-
this.
|
|
4275
|
-
this.messageQueue = [];
|
|
4363
|
+
this.rejectPending(new Error("Client explicitly disconnected"));
|
|
4276
4364
|
this.rpcHandlers.clear();
|
|
4277
4365
|
this.emit("disconnect", {});
|
|
4278
4366
|
}
|
|
@@ -4817,7 +4905,7 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
4817
4905
|
this.checkForToolChanges();
|
|
4818
4906
|
});
|
|
4819
4907
|
this.client.on("prompt", (prompt) => this.emit("prompt", prompt));
|
|
4820
|
-
this.client.on("disconnect", () => this.emit("disconnect", {}));
|
|
4908
|
+
this.client.on("disconnect", (payload) => this.emit("disconnect", payload || {}));
|
|
4821
4909
|
this.client.on("job.status", (data) => {
|
|
4822
4910
|
this.emit("job:status", data);
|
|
4823
4911
|
});
|
|
@@ -5744,6 +5832,8 @@ var Granular = class {
|
|
|
5744
5832
|
apiUrl;
|
|
5745
5833
|
httpUrl;
|
|
5746
5834
|
WebSocketCtor;
|
|
5835
|
+
onUnexpectedClose;
|
|
5836
|
+
onReconnectError;
|
|
5747
5837
|
/** Sandbox-level effect registry: sandboxId → (toolName → ToolWithHandler) */
|
|
5748
5838
|
sandboxEffects = /* @__PURE__ */ new Map();
|
|
5749
5839
|
/** Active environments tracker: sandboxId → Environment[] */
|
|
@@ -5760,6 +5850,8 @@ var Granular = class {
|
|
|
5760
5850
|
this.apiKey = auth;
|
|
5761
5851
|
this.apiUrl = options.apiUrl || "wss://api.granular.dev/v2/ws";
|
|
5762
5852
|
this.WebSocketCtor = options.WebSocketCtor;
|
|
5853
|
+
this.onUnexpectedClose = options.onUnexpectedClose;
|
|
5854
|
+
this.onReconnectError = options.onReconnectError;
|
|
5763
5855
|
this.httpUrl = this.apiUrl.replace("wss://", "https://").replace("/ws", "");
|
|
5764
5856
|
}
|
|
5765
5857
|
/**
|
|
@@ -5844,7 +5936,9 @@ var Granular = class {
|
|
|
5844
5936
|
url: this.apiUrl,
|
|
5845
5937
|
sessionId: envData.environmentId,
|
|
5846
5938
|
token: this.apiKey,
|
|
5847
|
-
WebSocketCtor: this.WebSocketCtor
|
|
5939
|
+
WebSocketCtor: this.WebSocketCtor,
|
|
5940
|
+
onUnexpectedClose: this.onUnexpectedClose,
|
|
5941
|
+
onReconnectError: this.onReconnectError
|
|
5848
5942
|
});
|
|
5849
5943
|
await client.connect();
|
|
5850
5944
|
const graphqlEndpoint = `${this.httpUrl}/orchestrator/graphql`;
|