@phpsandbox/sdk 0.0.33 → 0.0.35

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.
@@ -3147,6 +3147,89 @@ var PHPSandbox = (() => {
3147
3147
  );
3148
3148
  var reconnecting_websocket_mjs_default = ReconnectingWebSocket;
3149
3149
 
3150
+ // src/utils/websocket.ts
3151
+ var getReadyStateLabel = (state) => {
3152
+ if (typeof state !== "number") {
3153
+ return void 0;
3154
+ }
3155
+ return {
3156
+ 0: "CONNECTING",
3157
+ 1: "OPEN",
3158
+ 2: "CLOSING",
3159
+ 3: "CLOSED"
3160
+ }[state] ?? `STATE_${state}`;
3161
+ };
3162
+ var sanitizeWebSocketUrl = (value) => {
3163
+ try {
3164
+ const url = new URL(value);
3165
+ return `${url.origin}${url.pathname}`;
3166
+ } catch {
3167
+ return value;
3168
+ }
3169
+ };
3170
+ var extractNestedErrorMessage = (value) => {
3171
+ if (value instanceof Error) {
3172
+ return value.message ? `${value.name}: ${value.message}` : value.name;
3173
+ }
3174
+ if (typeof value === "string") {
3175
+ return value;
3176
+ }
3177
+ if (!value || typeof value !== "object") {
3178
+ return void 0;
3179
+ }
3180
+ const record = value;
3181
+ const message = typeof record.message === "string" && record.message ? record.message : typeof record.reason === "string" && record.reason ? record.reason : void 0;
3182
+ if (!message) {
3183
+ return void 0;
3184
+ }
3185
+ const name = typeof record.name === "string" && record.name ? record.name : void 0;
3186
+ return name ? `${name}: ${message}` : message;
3187
+ };
3188
+ var describeWebSocketEvent = (event) => {
3189
+ if (event instanceof Error) {
3190
+ return event.message ? `${event.name}: ${event.message}` : event.name;
3191
+ }
3192
+ if (typeof event === "string") {
3193
+ return event;
3194
+ }
3195
+ if (!event || typeof event !== "object") {
3196
+ return String(event);
3197
+ }
3198
+ const record = event;
3199
+ const parts = [];
3200
+ const topLevelMessage = extractNestedErrorMessage(record);
3201
+ if (topLevelMessage) {
3202
+ parts.push(topLevelMessage);
3203
+ }
3204
+ const nestedErrorMessage = extractNestedErrorMessage(record.error);
3205
+ if (nestedErrorMessage && nestedErrorMessage !== topLevelMessage) {
3206
+ parts.push(`error=${nestedErrorMessage}`);
3207
+ }
3208
+ if (typeof record.type === "string" && record.type) {
3209
+ parts.push(`type=${record.type}`);
3210
+ }
3211
+ if (typeof record.code === "number") {
3212
+ parts.push(`code=${record.code}`);
3213
+ }
3214
+ if (typeof record.reason === "string" && record.reason && record.reason !== topLevelMessage) {
3215
+ parts.push(`reason=${record.reason}`);
3216
+ }
3217
+ if (typeof record.wasClean === "boolean") {
3218
+ parts.push(`wasClean=${record.wasClean}`);
3219
+ }
3220
+ const target = record.target ?? record.currentTarget;
3221
+ if (target && typeof target === "object") {
3222
+ if (typeof target.url === "string" && target.url) {
3223
+ parts.push(`url=${sanitizeWebSocketUrl(target.url)}`);
3224
+ }
3225
+ const readyState = getReadyStateLabel(target.readyState);
3226
+ if (readyState) {
3227
+ parts.push(`readyState=${readyState}`);
3228
+ }
3229
+ }
3230
+ return parts.length > 0 ? parts.join(" | ") : "Unknown websocket event";
3231
+ };
3232
+
3150
3233
  // node_modules/isomorphic-ws/browser.js
3151
3234
  var ws = null;
3152
3235
  if (typeof WebSocket !== "undefined") {
@@ -3184,6 +3267,19 @@ var PHPSandbox = (() => {
3184
3267
  };
3185
3268
 
3186
3269
  // src/socket/index.ts
3270
+ var ConnectionTimeoutError = class extends Error {
3271
+ constructor(message = "WebSocket connection timeout") {
3272
+ super(message);
3273
+ this.name = "ConnectionTimeoutError";
3274
+ }
3275
+ };
3276
+ var ConnectionFailedError = class extends Error {
3277
+ constructor(message, originalError) {
3278
+ super(message);
3279
+ this.originalError = originalError;
3280
+ this.name = "ConnectionFailedError";
3281
+ }
3282
+ };
3187
3283
  var InvalidMessageError = class extends Error {
3188
3284
  constructor(message, data) {
3189
3285
  super(message);
@@ -3235,6 +3331,7 @@ var PHPSandbox = (() => {
3235
3331
  this.validateConfiguration(options);
3236
3332
  this.url = new URL(url);
3237
3333
  this.PING_INTERVAL = options.pingInterval ?? 3e4;
3334
+ this.CONNECT_WAIT_TIMEOUT = options.connectWaitTimeout ?? 3e4;
3238
3335
  this.connectionStats.connectionStartTime = Date.now();
3239
3336
  const startClosed = options.startClosed !== false;
3240
3337
  this.rws = new reconnecting_websocket_mjs_default(this.url.toString(), [], {
@@ -3264,6 +3361,9 @@ var PHPSandbox = (() => {
3264
3361
  if (options.connectionTimeout !== void 0 && (options.connectionTimeout < 100 || options.connectionTimeout > 3e4)) {
3265
3362
  throw new InvalidConfigurationError("connectionTimeout must be between 100ms and 30000ms");
3266
3363
  }
3364
+ if (options.connectWaitTimeout !== void 0 && (options.connectWaitTimeout < 1e3 || options.connectWaitTimeout > 3e5)) {
3365
+ throw new InvalidConfigurationError("connectWaitTimeout must be between 1000ms and 300000ms");
3366
+ }
3267
3367
  if (options.maxRetries !== void 0 && (options.maxRetries < 0 || options.maxRetries > 100)) {
3268
3368
  throw new InvalidConfigurationError("maxRetries must be between 0 and 100");
3269
3369
  }
@@ -3550,7 +3650,8 @@ var PHPSandbox = (() => {
3550
3650
  reject(new RateLimitError(_ev.reason || "Rate limit exceeded", _ev));
3551
3651
  return;
3552
3652
  }
3553
- reject(this.terminalError || new Error(`Connection lost to the notebook during request: ${_ev.reason || "Unknown reason"}`));
3653
+ const detail = describeWebSocketEvent(_ev);
3654
+ reject(this.terminalError || new ConnectionFailedError(`Connection lost to the notebook during request: ${detail}`, _ev));
3554
3655
  };
3555
3656
  this.rws.addEventListener("close", closeHandler);
3556
3657
  this.rws.addEventListener("error", closeHandler);
@@ -3738,8 +3839,10 @@ var PHPSandbox = (() => {
3738
3839
  });
3739
3840
  this.rws.addEventListener("error", (event) => {
3740
3841
  this.connectionStats.totalErrors++;
3842
+ const detail = describeWebSocketEvent(event);
3741
3843
  this.log("error", "Connection error", {
3742
- error: event,
3844
+ error: detail,
3845
+ rawError: event,
3743
3846
  totalErrors: this.connectionStats.totalErrors
3744
3847
  });
3745
3848
  });
@@ -3995,33 +4098,50 @@ var PHPSandbox = (() => {
3995
4098
  __privateMethod(this, _Transport_instances, startPeriodicPing_fn).call(this);
3996
4099
  return;
3997
4100
  }
3998
- if (this.rws.readyState === 3) {
3999
- this.rws.reconnect();
4000
- }
4001
4101
  let timeoutId;
4002
- const openHandler = () => {
4102
+ let errorCount = 0;
4103
+ const cleanup = () => {
4003
4104
  this.rws.removeEventListener("open", openHandler);
4004
4105
  this.rws.removeEventListener("error", errorHandler);
4106
+ this.rws.removeEventListener("close", closeHandler);
4005
4107
  clearTimeout(timeoutId);
4108
+ };
4109
+ const openHandler = () => {
4110
+ cleanup();
4006
4111
  this.connectPromise = null;
4007
4112
  resolve();
4008
4113
  __privateMethod(this, _Transport_instances, startPeriodicPing_fn).call(this);
4009
4114
  };
4010
4115
  const errorHandler = (error) => {
4011
- this.rws.removeEventListener("open", openHandler);
4012
- this.rws.removeEventListener("error", errorHandler);
4013
- clearTimeout(timeoutId);
4014
- this.connectPromise = null;
4015
- reject(new Error(`WebSocket connection failed: ${error}`));
4116
+ errorCount += 1;
4117
+ this.log("warn", "WebSocket emitted an error while connecting; waiting for reconnect/open", {
4118
+ errorCount,
4119
+ error: describeWebSocketEvent(error)
4120
+ });
4121
+ };
4122
+ const closeHandler = (event) => {
4123
+ const detail = describeWebSocketEvent(event);
4124
+ if ("code" in event && (event.code === 1008 || event.code === 4e3)) {
4125
+ cleanup();
4126
+ this.connectPromise = null;
4127
+ reject(new ConnectionFailedError(`WebSocket connection failed: ${detail}`, event));
4128
+ return;
4129
+ }
4130
+ this.log("warn", "WebSocket closed before opening; waiting for reconnect/open", {
4131
+ error: detail
4132
+ });
4016
4133
  };
4017
- timeoutId = setTimeout(() => {
4018
- this.rws.removeEventListener("open", openHandler);
4019
- this.rws.removeEventListener("error", errorHandler);
4020
- this.connectPromise = null;
4021
- reject(new Error("WebSocket connection timeout"));
4022
- }, 1e4);
4023
4134
  this.rws.addEventListener("open", openHandler);
4024
4135
  this.rws.addEventListener("error", errorHandler);
4136
+ this.rws.addEventListener("close", closeHandler);
4137
+ if (this.rws.readyState === 3) {
4138
+ this.rws.reconnect();
4139
+ }
4140
+ timeoutId = setTimeout(() => {
4141
+ cleanup();
4142
+ this.connectPromise = null;
4143
+ reject(new ConnectionTimeoutError(`WebSocket connection timeout after ${this.CONNECT_WAIT_TIMEOUT}ms`));
4144
+ }, this.CONNECT_WAIT_TIMEOUT);
4025
4145
  });
4026
4146
  return this.connectPromise;
4027
4147
  };