@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.
- package/dist/browser/phpsandbox-sdk.esm.js +112 -64
- package/dist/browser/phpsandbox-sdk.esm.js.map +3 -3
- package/dist/browser/phpsandbox-sdk.esm.min.js +2 -2
- package/dist/browser/phpsandbox-sdk.esm.min.js.map +3 -3
- package/dist/browser/phpsandbox-sdk.iife.js +112 -64
- package/dist/browser/phpsandbox-sdk.iife.js.map +3 -3
- package/dist/browser/phpsandbox-sdk.iife.min.js +2 -2
- package/dist/browser/phpsandbox-sdk.iife.min.js.map +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/socket/index.d.ts +1 -18
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +22 -40
- package/dist/socket/index.js.map +1 -1
- package/dist/terminal.d.ts +14 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +79 -22
- package/dist/terminal.js.map +1 -1
- package/package.json +1 -1
|
@@ -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.
|
|
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:
|
|
687
|
-
|
|
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
|
-
|
|
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
|
-
|
|
786
|
+
disposeInput();
|
|
716
787
|
resolve(data.exitCode);
|
|
717
788
|
})
|
|
718
789
|
);
|
|
719
790
|
});
|
|
720
791
|
const kill = once(() => {
|
|
721
|
-
|
|
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
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
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
|
}
|