@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
|
@@ -596,6 +596,8 @@ var once = (fn) => {
|
|
|
596
596
|
};
|
|
597
597
|
|
|
598
598
|
// src/terminal.ts
|
|
599
|
+
var TERMINAL_INPUT_FLUSH_DELAY_MS = 8;
|
|
600
|
+
var terminalInputFlushPattern = /[\x00-\x1f\x7f]/;
|
|
599
601
|
var Terminal = class {
|
|
600
602
|
constructor(okra) {
|
|
601
603
|
this.okra = okra;
|
|
@@ -619,13 +621,51 @@ var Terminal = class {
|
|
|
619
621
|
this.okra.listen(`terminal.output.${id}`, handler);
|
|
620
622
|
}
|
|
621
623
|
input(id, input) {
|
|
622
|
-
return this.okra.
|
|
624
|
+
return Promise.resolve(this.okra.send("terminal.input", { id, input }));
|
|
623
625
|
}
|
|
624
626
|
listen(event, handler) {
|
|
625
627
|
return this.okra.listen(event, handler);
|
|
626
628
|
}
|
|
629
|
+
async attach(id, opts) {
|
|
630
|
+
const handle = this.processHandle(id, opts?.abortSignal);
|
|
631
|
+
const task = await this.okra.invoke(
|
|
632
|
+
"terminal.attach",
|
|
633
|
+
{
|
|
634
|
+
id,
|
|
635
|
+
replayHistory: opts?.replayHistory
|
|
636
|
+
},
|
|
637
|
+
{ abortSignal: opts?.abortSignal }
|
|
638
|
+
);
|
|
639
|
+
if (!task) {
|
|
640
|
+
handle.dispose();
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
...handle.process,
|
|
645
|
+
...task
|
|
646
|
+
};
|
|
647
|
+
}
|
|
627
648
|
async spawn(command, args, opts) {
|
|
628
649
|
const id = opts?.id || nanoid();
|
|
650
|
+
const handle = this.processHandle(id, opts?.abortSignal);
|
|
651
|
+
const { abortSignal, ...otherOpts } = opts ?? {};
|
|
652
|
+
const result = await this.okra.invoke(
|
|
653
|
+
"terminal.spawn",
|
|
654
|
+
{
|
|
655
|
+
command: [command, ...args],
|
|
656
|
+
opts: {
|
|
657
|
+
id,
|
|
658
|
+
...otherOpts
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
{ abortSignal }
|
|
662
|
+
);
|
|
663
|
+
return {
|
|
664
|
+
...handle.process,
|
|
665
|
+
...result
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
processHandle(id, abortSignal) {
|
|
629
669
|
const disposables = /* @__PURE__ */ new Set();
|
|
630
670
|
const dispose = () => {
|
|
631
671
|
for (const disposable of disposables) {
|
|
@@ -633,11 +673,42 @@ var Terminal = class {
|
|
|
633
673
|
}
|
|
634
674
|
disposables.clear();
|
|
635
675
|
};
|
|
676
|
+
let pendingInput = "";
|
|
677
|
+
let inputFlushTimer;
|
|
678
|
+
const flushInput = () => {
|
|
679
|
+
if (inputFlushTimer) {
|
|
680
|
+
clearTimeout(inputFlushTimer);
|
|
681
|
+
inputFlushTimer = void 0;
|
|
682
|
+
}
|
|
683
|
+
if (pendingInput === "") {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
const input2 = pendingInput;
|
|
687
|
+
pendingInput = "";
|
|
688
|
+
void this.input(id, input2);
|
|
689
|
+
};
|
|
690
|
+
const scheduleInputFlush = () => {
|
|
691
|
+
if (inputFlushTimer) {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
inputFlushTimer = setTimeout(flushInput, TERMINAL_INPUT_FLUSH_DELAY_MS);
|
|
695
|
+
};
|
|
696
|
+
const queueInput = (chunk) => {
|
|
697
|
+
pendingInput += chunk;
|
|
698
|
+
if (terminalInputFlushPattern.test(chunk)) {
|
|
699
|
+
flushInput();
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
scheduleInputFlush();
|
|
703
|
+
};
|
|
704
|
+
const disposeInput = () => {
|
|
705
|
+
flushInput();
|
|
706
|
+
dispose();
|
|
707
|
+
};
|
|
636
708
|
const input = new WritableStream({
|
|
637
|
-
write:
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
close: dispose
|
|
709
|
+
write: queueInput,
|
|
710
|
+
close: disposeInput,
|
|
711
|
+
abort: disposeInput
|
|
641
712
|
});
|
|
642
713
|
let controller = null;
|
|
643
714
|
const output = new ReadableStream({
|
|
@@ -651,7 +722,7 @@ var Terminal = class {
|
|
|
651
722
|
},
|
|
652
723
|
cancel: () => {
|
|
653
724
|
controller = null;
|
|
654
|
-
|
|
725
|
+
disposeInput();
|
|
655
726
|
}
|
|
656
727
|
});
|
|
657
728
|
const exit = new Promise((resolve) => {
|
|
@@ -663,40 +734,30 @@ var Terminal = class {
|
|
|
663
734
|
} catch {
|
|
664
735
|
}
|
|
665
736
|
}
|
|
666
|
-
|
|
737
|
+
disposeInput();
|
|
667
738
|
resolve(data.exitCode);
|
|
668
739
|
})
|
|
669
740
|
);
|
|
670
741
|
});
|
|
671
742
|
const kill = once(() => {
|
|
672
|
-
|
|
743
|
+
disposeInput();
|
|
673
744
|
return this.okra.invoke("terminal.close", { id });
|
|
674
745
|
});
|
|
675
746
|
const resize = (dimensions) => {
|
|
676
747
|
this.okra.invoke("terminal.resize", { id, width: dimensions.cols, height: dimensions.rows });
|
|
677
748
|
};
|
|
678
|
-
const { abortSignal, ...otherOpts } = opts ?? {};
|
|
679
749
|
if (abortSignal) {
|
|
680
750
|
abortSignal.addEventListener("abort", kill);
|
|
681
751
|
}
|
|
682
|
-
const result = await this.okra.invoke(
|
|
683
|
-
"terminal.spawn",
|
|
684
|
-
{
|
|
685
|
-
command: [command, ...args],
|
|
686
|
-
opts: {
|
|
687
|
-
id,
|
|
688
|
-
...otherOpts
|
|
689
|
-
}
|
|
690
|
-
},
|
|
691
|
-
{ abortSignal }
|
|
692
|
-
);
|
|
693
752
|
return {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
753
|
+
process: {
|
|
754
|
+
exit,
|
|
755
|
+
input,
|
|
756
|
+
output,
|
|
757
|
+
kill,
|
|
758
|
+
resize
|
|
759
|
+
},
|
|
760
|
+
dispose: disposeInput
|
|
700
761
|
};
|
|
701
762
|
}
|
|
702
763
|
};
|
|
@@ -3250,6 +3311,7 @@ var InvalidConfigurationError = class extends Error {
|
|
|
3250
3311
|
};
|
|
3251
3312
|
var _Transport_instances, connect_fn, startPeriodicPing_fn;
|
|
3252
3313
|
var Transport = class {
|
|
3314
|
+
// 30 seconds
|
|
3253
3315
|
constructor(url, eventEmitter, options = {}) {
|
|
3254
3316
|
this.eventEmitter = eventEmitter;
|
|
3255
3317
|
this.options = options;
|
|
@@ -3275,14 +3337,6 @@ var Transport = class {
|
|
|
3275
3337
|
this.messageQueue = [];
|
|
3276
3338
|
this.MAX_QUEUE_SIZE = 100;
|
|
3277
3339
|
this.QUEUE_TIMEOUT = 3e4;
|
|
3278
|
-
// 30 seconds
|
|
3279
|
-
// Rate limiting
|
|
3280
|
-
this.rateLimiter = {
|
|
3281
|
-
requests: [],
|
|
3282
|
-
maxRequests: 50,
|
|
3283
|
-
windowMs: 1e3
|
|
3284
|
-
// 1 second
|
|
3285
|
-
};
|
|
3286
3340
|
this.validateConfiguration(options);
|
|
3287
3341
|
this.url = new URL(url);
|
|
3288
3342
|
this.PING_INTERVAL = options.pingInterval ?? 3e4;
|
|
@@ -3534,9 +3588,6 @@ var Transport = class {
|
|
|
3534
3588
|
if (this.terminalError) {
|
|
3535
3589
|
throw this.terminalError;
|
|
3536
3590
|
}
|
|
3537
|
-
if (this.isRateLimited()) {
|
|
3538
|
-
throw new RateLimitError("Rate limit exceeded - too many requests");
|
|
3539
|
-
}
|
|
3540
3591
|
this.clearOldQueuedMessages();
|
|
3541
3592
|
const responseEvent = options.responseEvent || `${action}_${nanoid()}_response`;
|
|
3542
3593
|
const errorEvent = `${responseEvent}_error`;
|
|
@@ -3633,6 +3684,27 @@ var Transport = class {
|
|
|
3633
3684
|
};
|
|
3634
3685
|
return this.sendWithRetry(async () => await send(), options.retries || 10);
|
|
3635
3686
|
}
|
|
3687
|
+
send(action, data = {}) {
|
|
3688
|
+
if (this.terminalError) {
|
|
3689
|
+
throw this.terminalError;
|
|
3690
|
+
}
|
|
3691
|
+
if (!this.isConnected || this.isClosed) {
|
|
3692
|
+
this.log("debug", "Connection not available, dropping one-way message", {
|
|
3693
|
+
action
|
|
3694
|
+
});
|
|
3695
|
+
return false;
|
|
3696
|
+
}
|
|
3697
|
+
try {
|
|
3698
|
+
this.rws.send(this.pack({ action, data }));
|
|
3699
|
+
this.connectionStats.totalMessages++;
|
|
3700
|
+
this.log("debug", "One-way message sent", { action, data });
|
|
3701
|
+
return true;
|
|
3702
|
+
} catch (error) {
|
|
3703
|
+
this.connectionStats.totalErrors++;
|
|
3704
|
+
this.log("error", "Failed to send one-way message", { action, error });
|
|
3705
|
+
return false;
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3636
3708
|
pack(data) {
|
|
3637
3709
|
return new Blob([encode(data)]);
|
|
3638
3710
|
}
|
|
@@ -3736,7 +3808,6 @@ var Transport = class {
|
|
|
3736
3808
|
if (queuedCount > 0) {
|
|
3737
3809
|
this.log("debug", `Rejected ${queuedCount} queued messages due to connection close`);
|
|
3738
3810
|
}
|
|
3739
|
-
this.rateLimiter.requests = [];
|
|
3740
3811
|
this.disposables.dispose();
|
|
3741
3812
|
try {
|
|
3742
3813
|
this.rws.close(code, reason);
|
|
@@ -3863,18 +3934,6 @@ var Transport = class {
|
|
|
3863
3934
|
this.log("debug", `Cleared ${originalLength - this.messageQueue.length} expired messages`);
|
|
3864
3935
|
}
|
|
3865
3936
|
}
|
|
3866
|
-
/**
|
|
3867
|
-
* Rate limiting check
|
|
3868
|
-
*/
|
|
3869
|
-
isRateLimited() {
|
|
3870
|
-
const now = Date.now();
|
|
3871
|
-
this.rateLimiter.requests = this.rateLimiter.requests.filter((timestamp) => now - timestamp < this.rateLimiter.windowMs);
|
|
3872
|
-
if (this.rateLimiter.requests.length >= this.rateLimiter.maxRequests) {
|
|
3873
|
-
return true;
|
|
3874
|
-
}
|
|
3875
|
-
this.rateLimiter.requests.push(now);
|
|
3876
|
-
return false;
|
|
3877
|
-
}
|
|
3878
3937
|
/**
|
|
3879
3938
|
* Calculate exponential backoff delay
|
|
3880
3939
|
*/
|
|
@@ -3909,12 +3968,6 @@ var Transport = class {
|
|
|
3909
3968
|
maxSize: this.MAX_QUEUE_SIZE,
|
|
3910
3969
|
oldestMessageAge: this.messageQueue.length > 0 ? now - Math.min(...this.messageQueue.map((m) => m.timestamp)) : 0
|
|
3911
3970
|
},
|
|
3912
|
-
rateLimiter: {
|
|
3913
|
-
currentRequests: this.rateLimiter.requests.length,
|
|
3914
|
-
maxRequests: this.rateLimiter.maxRequests,
|
|
3915
|
-
windowMs: this.rateLimiter.windowMs,
|
|
3916
|
-
isLimited: this.isRateLimited()
|
|
3917
|
-
},
|
|
3918
3971
|
config: {
|
|
3919
3972
|
pingInterval: this.PING_INTERVAL,
|
|
3920
3973
|
queueTimeout: this.QUEUE_TIMEOUT,
|
|
@@ -3980,10 +4033,6 @@ var Transport = class {
|
|
|
3980
4033
|
issues.push("High average response time");
|
|
3981
4034
|
recommendations.push("Check network latency and server performance");
|
|
3982
4035
|
}
|
|
3983
|
-
if (metrics.rateLimiter.isLimited) {
|
|
3984
|
-
issues.push("Rate limiting is active");
|
|
3985
|
-
recommendations.push("Reduce request frequency or increase rate limit");
|
|
3986
|
-
}
|
|
3987
4036
|
this.log("info", "Connection diagnostics completed", {
|
|
3988
4037
|
status,
|
|
3989
4038
|
issueCount: issues.length,
|
|
@@ -4004,10 +4053,6 @@ var Transport = class {
|
|
|
4004
4053
|
const maintenanceInterval = setInterval(
|
|
4005
4054
|
() => {
|
|
4006
4055
|
this.clearOldQueuedMessages();
|
|
4007
|
-
const now = Date.now();
|
|
4008
|
-
this.rateLimiter.requests = this.rateLimiter.requests.filter(
|
|
4009
|
-
(timestamp) => now - timestamp < this.rateLimiter.windowMs
|
|
4010
|
-
);
|
|
4011
4056
|
if (this.options.debug) {
|
|
4012
4057
|
const health = this.getHealthStatus();
|
|
4013
4058
|
const metrics = this.getConnectionMetrics();
|
|
@@ -5187,6 +5232,9 @@ var NotebookInstance = class {
|
|
|
5187
5232
|
invoke(action, data = {}, options = {}) {
|
|
5188
5233
|
return this.socket.invoke(action, data || {}, options);
|
|
5189
5234
|
}
|
|
5235
|
+
send(action, data = {}) {
|
|
5236
|
+
return this.socket.send(action, data || {});
|
|
5237
|
+
}
|
|
5190
5238
|
ping() {
|
|
5191
5239
|
return this.invoke("ping");
|
|
5192
5240
|
}
|