@phpsandbox/sdk 0.0.32 → 0.0.34

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.
@@ -684,19 +684,30 @@ var PHPSandbox = (() => {
684
684
  },
685
685
  close: dispose
686
686
  });
687
+ let controller = null;
687
688
  const output = new ReadableStream({
688
- start: (controller) => {
689
+ start: (_controller) => {
690
+ controller = _controller;
689
691
  disposables.add(
690
692
  this.listen(`terminal.output.${id}`, (data) => {
691
- controller.enqueue(data.output);
693
+ controller?.enqueue(data.output);
692
694
  })
693
695
  );
694
696
  },
695
- cancel: dispose
697
+ cancel: () => {
698
+ controller = null;
699
+ dispose();
700
+ }
696
701
  });
697
702
  const exit = new Promise((resolve) => {
698
703
  disposables.add(
699
704
  this.listen(`terminal.close.${id}`, (data) => {
705
+ if (controller) {
706
+ try {
707
+ controller.close();
708
+ } catch {
709
+ }
710
+ }
700
711
  dispose();
701
712
  resolve(data.exitCode);
702
713
  })
@@ -3136,6 +3147,89 @@ var PHPSandbox = (() => {
3136
3147
  );
3137
3148
  var reconnecting_websocket_mjs_default = ReconnectingWebSocket;
3138
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
+
3139
3233
  // node_modules/isomorphic-ws/browser.js
3140
3234
  var ws = null;
3141
3235
  if (typeof WebSocket !== "undefined") {
@@ -3173,6 +3267,13 @@ var PHPSandbox = (() => {
3173
3267
  };
3174
3268
 
3175
3269
  // src/socket/index.ts
3270
+ var ConnectionFailedError = class extends Error {
3271
+ constructor(message, originalError) {
3272
+ super(message);
3273
+ this.originalError = originalError;
3274
+ this.name = "ConnectionFailedError";
3275
+ }
3276
+ };
3176
3277
  var InvalidMessageError = class extends Error {
3177
3278
  constructor(message, data) {
3178
3279
  super(message);
@@ -3227,7 +3328,7 @@ var PHPSandbox = (() => {
3227
3328
  this.connectionStats.connectionStartTime = Date.now();
3228
3329
  const startClosed = options.startClosed !== false;
3229
3330
  this.rws = new reconnecting_websocket_mjs_default(this.url.toString(), [], {
3230
- WebSocket: globalThis.WebSocket ?? browser_default,
3331
+ WebSocket: options.webSocket ?? globalThis.WebSocket ?? browser_default,
3231
3332
  connectionTimeout: options.connectionTimeout,
3232
3333
  maxReconnectionDelay: 2e3,
3233
3334
  minReconnectionDelay: 200,
@@ -3282,7 +3383,19 @@ var PHPSandbox = (() => {
3282
3383
  async registerWatchers() {
3283
3384
  const onMessage = (ev) => {
3284
3385
  if (!(ev.data instanceof Blob)) {
3285
- throw new Error("Unexpected message type: " + typeof ev.data);
3386
+ const error = new Error("Unexpected message type: " + typeof ev.data);
3387
+ this.connectionStats.totalErrors++;
3388
+ this.log("error", "Unexpected WebSocket message type", {
3389
+ error: error.message,
3390
+ messageType: typeof ev.data
3391
+ });
3392
+ this.eventEmitter.emit("transport.error", {
3393
+ type: "message_type_error",
3394
+ error,
3395
+ rawMessage: ev.data,
3396
+ timestamp: Date.now()
3397
+ });
3398
+ return;
3286
3399
  }
3287
3400
  ev.data.arrayBuffer().then((buffer) => {
3288
3401
  if (buffer.byteLength === 0) {
@@ -3290,7 +3403,19 @@ var PHPSandbox = (() => {
3290
3403
  return;
3291
3404
  }
3292
3405
  try {
3293
- this.handleRawMessage(decode(buffer));
3406
+ void this.handleRawMessage(decode(buffer)).catch((error) => {
3407
+ this.connectionStats.totalErrors++;
3408
+ this.log("error", "Failed to process WebSocket frame", {
3409
+ error: error instanceof Error ? error.message : String(error),
3410
+ byteLength: buffer.byteLength
3411
+ });
3412
+ this.eventEmitter.emit("transport.error", {
3413
+ type: "message_handle_error",
3414
+ error,
3415
+ rawMessage: buffer,
3416
+ timestamp: Date.now()
3417
+ });
3418
+ });
3294
3419
  } catch (error) {
3295
3420
  this.connectionStats.totalErrors++;
3296
3421
  this.log("error", "Failed to decode WebSocket frame", {
@@ -3314,6 +3439,10 @@ var PHPSandbox = (() => {
3314
3439
  });
3315
3440
  }
3316
3441
  async handleRawMessage(ev) {
3442
+ if (this.closed) {
3443
+ this.log("debug", "Ignoring message received after transport was closed");
3444
+ return;
3445
+ }
3317
3446
  if (typeof ev !== "object" || ev === null) {
3318
3447
  this.log("debug", "Received invalid message format", { ev });
3319
3448
  return;
@@ -3511,7 +3640,8 @@ var PHPSandbox = (() => {
3511
3640
  reject(new RateLimitError(_ev.reason || "Rate limit exceeded", _ev));
3512
3641
  return;
3513
3642
  }
3514
- reject(this.terminalError || new Error(`Connection lost to the notebook during request: ${_ev.reason || "Unknown reason"}`));
3643
+ const detail = describeWebSocketEvent(_ev);
3644
+ reject(this.terminalError || new ConnectionFailedError(`Connection lost to the notebook during request: ${detail}`, _ev));
3515
3645
  };
3516
3646
  this.rws.addEventListener("close", closeHandler);
3517
3647
  this.rws.addEventListener("error", closeHandler);
@@ -3699,8 +3829,10 @@ var PHPSandbox = (() => {
3699
3829
  });
3700
3830
  this.rws.addEventListener("error", (event) => {
3701
3831
  this.connectionStats.totalErrors++;
3832
+ const detail = describeWebSocketEvent(event);
3702
3833
  this.log("error", "Connection error", {
3703
- error: event,
3834
+ error: detail,
3835
+ rawError: event,
3704
3836
  totalErrors: this.connectionStats.totalErrors
3705
3837
  });
3706
3838
  });
@@ -3973,7 +4105,8 @@ var PHPSandbox = (() => {
3973
4105
  this.rws.removeEventListener("error", errorHandler);
3974
4106
  clearTimeout(timeoutId);
3975
4107
  this.connectPromise = null;
3976
- reject(new Error(`WebSocket connection failed: ${error}`));
4108
+ const detail = describeWebSocketEvent(error);
4109
+ reject(new ConnectionFailedError(`WebSocket connection failed: ${detail}`, error));
3977
4110
  };
3978
4111
  timeoutId = setTimeout(() => {
3979
4112
  this.rws.removeEventListener("open", openHandler);
@@ -4975,7 +5108,8 @@ var PHPSandbox = (() => {
4975
5108
  this.emitter = EventManager.createInstance();
4976
5109
  this.socket = new Transport(data.okraUrl, this.emitter, {
4977
5110
  debug: client.options.debug,
4978
- startClosed: client.options.startClosed
5111
+ startClosed: client.options.startClosed,
5112
+ webSocket: client.options.webSocket
4979
5113
  });
4980
5114
  this.watchConnection();
4981
5115
  __privateSet(this, _initPromise, __privateMethod(this, _NotebookInstance_instances, init_fn).call(this));
@@ -5143,6 +5277,8 @@ var PHPSandbox = (() => {
5143
5277
  reject(error);
5144
5278
  });
5145
5279
  }));
5280
+ void __privateGet(this, _initPromise).catch(() => {
5281
+ });
5146
5282
  return __privateGet(this, _initPromise);
5147
5283
  };
5148
5284
  var NotebookSecrets = class {