@phpsandbox/sdk 0.0.37 → 0.0.39

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.
@@ -645,6 +645,8 @@ var PHPSandbox = (() => {
645
645
  };
646
646
 
647
647
  // src/terminal.ts
648
+ var TERMINAL_INPUT_FLUSH_DELAY_MS = 8;
649
+ var terminalInputFlushPattern = /[\x00-\x1f\x7f]/;
648
650
  var Terminal = class {
649
651
  constructor(okra) {
650
652
  this.okra = okra;
@@ -668,13 +670,51 @@ var PHPSandbox = (() => {
668
670
  this.okra.listen(`terminal.output.${id}`, handler);
669
671
  }
670
672
  input(id, input) {
671
- return this.okra.invoke("terminal.input", { id, input });
673
+ return Promise.resolve(this.okra.send("terminal.input", { id, input }));
672
674
  }
673
675
  listen(event, handler) {
674
676
  return this.okra.listen(event, handler);
675
677
  }
678
+ async attach(id, opts) {
679
+ const handle = this.processHandle(id, opts?.abortSignal);
680
+ const task = await this.okra.invoke(
681
+ "terminal.attach",
682
+ {
683
+ id,
684
+ replayHistory: opts?.replayHistory
685
+ },
686
+ { abortSignal: opts?.abortSignal }
687
+ );
688
+ if (!task) {
689
+ handle.dispose();
690
+ return false;
691
+ }
692
+ return {
693
+ ...handle.process,
694
+ ...task
695
+ };
696
+ }
676
697
  async spawn(command, args, opts) {
677
698
  const id = opts?.id || nanoid();
699
+ const handle = this.processHandle(id, opts?.abortSignal);
700
+ const { abortSignal, ...otherOpts } = opts ?? {};
701
+ const result = await this.okra.invoke(
702
+ "terminal.spawn",
703
+ {
704
+ command: [command, ...args],
705
+ opts: {
706
+ id,
707
+ ...otherOpts
708
+ }
709
+ },
710
+ { abortSignal }
711
+ );
712
+ return {
713
+ ...handle.process,
714
+ ...result
715
+ };
716
+ }
717
+ processHandle(id, abortSignal) {
678
718
  const disposables = /* @__PURE__ */ new Set();
679
719
  const dispose = () => {
680
720
  for (const disposable of disposables) {
@@ -682,11 +722,42 @@ var PHPSandbox = (() => {
682
722
  }
683
723
  disposables.clear();
684
724
  };
725
+ let pendingInput = "";
726
+ let inputFlushTimer;
727
+ const flushInput = () => {
728
+ if (inputFlushTimer) {
729
+ clearTimeout(inputFlushTimer);
730
+ inputFlushTimer = void 0;
731
+ }
732
+ if (pendingInput === "") {
733
+ return;
734
+ }
735
+ const input2 = pendingInput;
736
+ pendingInput = "";
737
+ void this.input(id, input2);
738
+ };
739
+ const scheduleInputFlush = () => {
740
+ if (inputFlushTimer) {
741
+ return;
742
+ }
743
+ inputFlushTimer = setTimeout(flushInput, TERMINAL_INPUT_FLUSH_DELAY_MS);
744
+ };
745
+ const queueInput = (chunk) => {
746
+ pendingInput += chunk;
747
+ if (terminalInputFlushPattern.test(chunk)) {
748
+ flushInput();
749
+ return;
750
+ }
751
+ scheduleInputFlush();
752
+ };
753
+ const disposeInput = () => {
754
+ flushInput();
755
+ dispose();
756
+ };
685
757
  const input = new WritableStream({
686
- write: (chunk) => {
687
- this.input(id, chunk);
688
- },
689
- close: dispose
758
+ write: queueInput,
759
+ close: disposeInput,
760
+ abort: disposeInput
690
761
  });
691
762
  let controller = null;
692
763
  const output = new ReadableStream({
@@ -700,7 +771,7 @@ var PHPSandbox = (() => {
700
771
  },
701
772
  cancel: () => {
702
773
  controller = null;
703
- dispose();
774
+ disposeInput();
704
775
  }
705
776
  });
706
777
  const exit = new Promise((resolve) => {
@@ -712,40 +783,30 @@ var PHPSandbox = (() => {
712
783
  } catch {
713
784
  }
714
785
  }
715
- dispose();
786
+ disposeInput();
716
787
  resolve(data.exitCode);
717
788
  })
718
789
  );
719
790
  });
720
791
  const kill = once(() => {
721
- dispose();
792
+ disposeInput();
722
793
  return this.okra.invoke("terminal.close", { id });
723
794
  });
724
795
  const resize = (dimensions) => {
725
796
  this.okra.invoke("terminal.resize", { id, width: dimensions.cols, height: dimensions.rows });
726
797
  };
727
- const { abortSignal, ...otherOpts } = opts ?? {};
728
798
  if (abortSignal) {
729
799
  abortSignal.addEventListener("abort", kill);
730
800
  }
731
- const result = await this.okra.invoke(
732
- "terminal.spawn",
733
- {
734
- command: [command, ...args],
735
- opts: {
736
- id,
737
- ...otherOpts
738
- }
739
- },
740
- { abortSignal }
741
- );
742
801
  return {
743
- exit,
744
- input,
745
- output,
746
- kill,
747
- resize,
748
- ...result
802
+ process: {
803
+ exit,
804
+ input,
805
+ output,
806
+ kill,
807
+ resize
808
+ },
809
+ dispose: disposeInput
749
810
  };
750
811
  }
751
812
  };
@@ -3299,6 +3360,7 @@ var PHPSandbox = (() => {
3299
3360
  };
3300
3361
  var _Transport_instances, connect_fn, startPeriodicPing_fn;
3301
3362
  var Transport = class {
3363
+ // 30 seconds
3302
3364
  constructor(url, eventEmitter, options = {}) {
3303
3365
  this.eventEmitter = eventEmitter;
3304
3366
  this.options = options;
@@ -3324,14 +3386,6 @@ var PHPSandbox = (() => {
3324
3386
  this.messageQueue = [];
3325
3387
  this.MAX_QUEUE_SIZE = 100;
3326
3388
  this.QUEUE_TIMEOUT = 3e4;
3327
- // 30 seconds
3328
- // Rate limiting
3329
- this.rateLimiter = {
3330
- requests: [],
3331
- maxRequests: 50,
3332
- windowMs: 1e3
3333
- // 1 second
3334
- };
3335
3389
  this.validateConfiguration(options);
3336
3390
  this.url = new URL(url);
3337
3391
  this.PING_INTERVAL = options.pingInterval ?? 3e4;
@@ -3583,9 +3637,6 @@ var PHPSandbox = (() => {
3583
3637
  if (this.terminalError) {
3584
3638
  throw this.terminalError;
3585
3639
  }
3586
- if (this.isRateLimited()) {
3587
- throw new RateLimitError("Rate limit exceeded - too many requests");
3588
- }
3589
3640
  this.clearOldQueuedMessages();
3590
3641
  const responseEvent = options.responseEvent || `${action}_${nanoid()}_response`;
3591
3642
  const errorEvent = `${responseEvent}_error`;
@@ -3682,6 +3733,27 @@ var PHPSandbox = (() => {
3682
3733
  };
3683
3734
  return this.sendWithRetry(async () => await send(), options.retries || 10);
3684
3735
  }
3736
+ send(action, data = {}) {
3737
+ if (this.terminalError) {
3738
+ throw this.terminalError;
3739
+ }
3740
+ if (!this.isConnected || this.isClosed) {
3741
+ this.log("debug", "Connection not available, dropping one-way message", {
3742
+ action
3743
+ });
3744
+ return false;
3745
+ }
3746
+ try {
3747
+ this.rws.send(this.pack({ action, data }));
3748
+ this.connectionStats.totalMessages++;
3749
+ this.log("debug", "One-way message sent", { action, data });
3750
+ return true;
3751
+ } catch (error) {
3752
+ this.connectionStats.totalErrors++;
3753
+ this.log("error", "Failed to send one-way message", { action, error });
3754
+ return false;
3755
+ }
3756
+ }
3685
3757
  pack(data) {
3686
3758
  return new Blob([encode(data)]);
3687
3759
  }
@@ -3785,7 +3857,6 @@ var PHPSandbox = (() => {
3785
3857
  if (queuedCount > 0) {
3786
3858
  this.log("debug", `Rejected ${queuedCount} queued messages due to connection close`);
3787
3859
  }
3788
- this.rateLimiter.requests = [];
3789
3860
  this.disposables.dispose();
3790
3861
  try {
3791
3862
  this.rws.close(code, reason);
@@ -3912,18 +3983,6 @@ var PHPSandbox = (() => {
3912
3983
  this.log("debug", `Cleared ${originalLength - this.messageQueue.length} expired messages`);
3913
3984
  }
3914
3985
  }
3915
- /**
3916
- * Rate limiting check
3917
- */
3918
- isRateLimited() {
3919
- const now = Date.now();
3920
- this.rateLimiter.requests = this.rateLimiter.requests.filter((timestamp) => now - timestamp < this.rateLimiter.windowMs);
3921
- if (this.rateLimiter.requests.length >= this.rateLimiter.maxRequests) {
3922
- return true;
3923
- }
3924
- this.rateLimiter.requests.push(now);
3925
- return false;
3926
- }
3927
3986
  /**
3928
3987
  * Calculate exponential backoff delay
3929
3988
  */
@@ -3958,12 +4017,6 @@ var PHPSandbox = (() => {
3958
4017
  maxSize: this.MAX_QUEUE_SIZE,
3959
4018
  oldestMessageAge: this.messageQueue.length > 0 ? now - Math.min(...this.messageQueue.map((m) => m.timestamp)) : 0
3960
4019
  },
3961
- rateLimiter: {
3962
- currentRequests: this.rateLimiter.requests.length,
3963
- maxRequests: this.rateLimiter.maxRequests,
3964
- windowMs: this.rateLimiter.windowMs,
3965
- isLimited: this.isRateLimited()
3966
- },
3967
4020
  config: {
3968
4021
  pingInterval: this.PING_INTERVAL,
3969
4022
  queueTimeout: this.QUEUE_TIMEOUT,
@@ -4029,10 +4082,6 @@ var PHPSandbox = (() => {
4029
4082
  issues.push("High average response time");
4030
4083
  recommendations.push("Check network latency and server performance");
4031
4084
  }
4032
- if (metrics.rateLimiter.isLimited) {
4033
- issues.push("Rate limiting is active");
4034
- recommendations.push("Reduce request frequency or increase rate limit");
4035
- }
4036
4085
  this.log("info", "Connection diagnostics completed", {
4037
4086
  status,
4038
4087
  issueCount: issues.length,
@@ -4053,10 +4102,6 @@ var PHPSandbox = (() => {
4053
4102
  const maintenanceInterval = setInterval(
4054
4103
  () => {
4055
4104
  this.clearOldQueuedMessages();
4056
- const now = Date.now();
4057
- this.rateLimiter.requests = this.rateLimiter.requests.filter(
4058
- (timestamp) => now - timestamp < this.rateLimiter.windowMs
4059
- );
4060
4105
  if (this.options.debug) {
4061
4106
  const health = this.getHealthStatus();
4062
4107
  const metrics = this.getConnectionMetrics();
@@ -5236,6 +5281,9 @@ var PHPSandbox = (() => {
5236
5281
  invoke(action, data = {}, options = {}) {
5237
5282
  return this.socket.invoke(action, data || {}, options);
5238
5283
  }
5284
+ send(action, data = {}) {
5285
+ return this.socket.send(action, data || {});
5286
+ }
5239
5287
  ping() {
5240
5288
  return this.invoke("ping");
5241
5289
  }