@phpsandbox/sdk 0.0.32 → 0.0.33

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/README.md CHANGED
@@ -79,12 +79,20 @@ await fetched.ready();
79
79
 
80
80
  const forked = await created.fork();
81
81
  await forked.delete();
82
+
83
+ const persistent = await client.notebook.create('laravel', {
84
+ title: 'Persistent Laravel',
85
+ persistent: true,
86
+ });
87
+
88
+ console.log(persistent.data.policy);
82
89
  ```
83
90
 
84
91
  Notes:
85
92
 
86
93
  - `create()` and `fork()` initialize automatically.
87
94
  - `open()` and `get()` return a notebook instance; call `await notebook.ready()` before using tools.
95
+ - API notebook creates are ephemeral by default. `persistent: true` requires an entitled account.
88
96
 
89
97
  ## Services At A Glance
90
98
 
@@ -103,6 +111,12 @@ Each `NotebookInstance` exposes service clients:
103
111
  - `notebook.log` (`Log`)
104
112
  - `notebook.services` (`Services`)
105
113
 
114
+ Notes:
115
+
116
+ - `terminal.spawn()` and `shell.exec()` are part of the current okra websocket action set. `terminal.start` currently is not.
117
+ - `notebook.repl.eval()` is part of the current okra websocket action set. `repl.start` is currently not.
118
+ - `notebook.laravel` is exposed by the SDK, but the current okra websocket action set does not expose Laravel maintenance actions.
119
+
106
120
  ## Common Operations
107
121
 
108
122
  ### Files
@@ -639,19 +639,30 @@ var Terminal = class {
639
639
  },
640
640
  close: dispose
641
641
  });
642
+ let controller = null;
642
643
  const output = new ReadableStream({
643
- start: (controller) => {
644
+ start: (_controller) => {
645
+ controller = _controller;
644
646
  disposables.add(
645
647
  this.listen(`terminal.output.${id}`, (data) => {
646
- controller.enqueue(data.output);
648
+ controller?.enqueue(data.output);
647
649
  })
648
650
  );
649
651
  },
650
- cancel: dispose
652
+ cancel: () => {
653
+ controller = null;
654
+ dispose();
655
+ }
651
656
  });
652
657
  const exit = new Promise((resolve) => {
653
658
  disposables.add(
654
659
  this.listen(`terminal.close.${id}`, (data) => {
660
+ if (controller) {
661
+ try {
662
+ controller.close();
663
+ } catch {
664
+ }
665
+ }
655
666
  dispose();
656
667
  resolve(data.exitCode);
657
668
  })
@@ -3182,7 +3193,7 @@ var Transport = class {
3182
3193
  this.connectionStats.connectionStartTime = Date.now();
3183
3194
  const startClosed = options.startClosed !== false;
3184
3195
  this.rws = new reconnecting_websocket_mjs_default(this.url.toString(), [], {
3185
- WebSocket: globalThis.WebSocket ?? browser_default,
3196
+ WebSocket: options.webSocket ?? globalThis.WebSocket ?? browser_default,
3186
3197
  connectionTimeout: options.connectionTimeout,
3187
3198
  maxReconnectionDelay: 2e3,
3188
3199
  minReconnectionDelay: 200,
@@ -3237,7 +3248,19 @@ var Transport = class {
3237
3248
  async registerWatchers() {
3238
3249
  const onMessage = (ev) => {
3239
3250
  if (!(ev.data instanceof Blob)) {
3240
- throw new Error("Unexpected message type: " + typeof ev.data);
3251
+ const error = new Error("Unexpected message type: " + typeof ev.data);
3252
+ this.connectionStats.totalErrors++;
3253
+ this.log("error", "Unexpected WebSocket message type", {
3254
+ error: error.message,
3255
+ messageType: typeof ev.data
3256
+ });
3257
+ this.eventEmitter.emit("transport.error", {
3258
+ type: "message_type_error",
3259
+ error,
3260
+ rawMessage: ev.data,
3261
+ timestamp: Date.now()
3262
+ });
3263
+ return;
3241
3264
  }
3242
3265
  ev.data.arrayBuffer().then((buffer) => {
3243
3266
  if (buffer.byteLength === 0) {
@@ -3245,7 +3268,19 @@ var Transport = class {
3245
3268
  return;
3246
3269
  }
3247
3270
  try {
3248
- this.handleRawMessage(decode(buffer));
3271
+ void this.handleRawMessage(decode(buffer)).catch((error) => {
3272
+ this.connectionStats.totalErrors++;
3273
+ this.log("error", "Failed to process WebSocket frame", {
3274
+ error: error instanceof Error ? error.message : String(error),
3275
+ byteLength: buffer.byteLength
3276
+ });
3277
+ this.eventEmitter.emit("transport.error", {
3278
+ type: "message_handle_error",
3279
+ error,
3280
+ rawMessage: buffer,
3281
+ timestamp: Date.now()
3282
+ });
3283
+ });
3249
3284
  } catch (error) {
3250
3285
  this.connectionStats.totalErrors++;
3251
3286
  this.log("error", "Failed to decode WebSocket frame", {
@@ -3269,6 +3304,10 @@ var Transport = class {
3269
3304
  });
3270
3305
  }
3271
3306
  async handleRawMessage(ev) {
3307
+ if (this.closed) {
3308
+ this.log("debug", "Ignoring message received after transport was closed");
3309
+ return;
3310
+ }
3272
3311
  if (typeof ev !== "object" || ev === null) {
3273
3312
  this.log("debug", "Received invalid message format", { ev });
3274
3313
  return;
@@ -4930,7 +4969,8 @@ var NotebookInstance = class {
4930
4969
  this.emitter = EventManager.createInstance();
4931
4970
  this.socket = new Transport(data.okraUrl, this.emitter, {
4932
4971
  debug: client.options.debug,
4933
- startClosed: client.options.startClosed
4972
+ startClosed: client.options.startClosed,
4973
+ webSocket: client.options.webSocket
4934
4974
  });
4935
4975
  this.watchConnection();
4936
4976
  __privateSet(this, _initPromise, __privateMethod(this, _NotebookInstance_instances, init_fn).call(this));
@@ -5098,6 +5138,8 @@ init_fn = function() {
5098
5138
  reject(error);
5099
5139
  });
5100
5140
  }));
5141
+ void __privateGet(this, _initPromise).catch(() => {
5142
+ });
5101
5143
  return __privateGet(this, _initPromise);
5102
5144
  };
5103
5145
  var NotebookSecrets = class {