@phpsandbox/sdk 0.0.29 → 0.0.30
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 +18 -0
- package/dist/browser/phpsandbox-sdk.esm.js +187 -6
- 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 +4 -4
- package/dist/browser/phpsandbox-sdk.iife.js +187 -6
- 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 +4 -4
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +7 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -1
- package/dist/index.js.map +1 -1
- package/dist/services.d.ts +78 -0
- package/dist/services.d.ts.map +1 -0
- package/dist/services.js +102 -0
- package/dist/services.js.map +1 -0
- package/dist/socket/index.d.ts +9 -0
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +46 -5
- package/dist/socket/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,6 +101,7 @@ Each `NotebookInstance` exposes service clients:
|
|
|
101
101
|
- `notebook.laravel` (`Laravel`)
|
|
102
102
|
- `notebook.auth` (`Auth`)
|
|
103
103
|
- `notebook.log` (`Log`)
|
|
104
|
+
- `notebook.services` (`Services`)
|
|
104
105
|
|
|
105
106
|
## Common Operations
|
|
106
107
|
|
|
@@ -144,6 +145,23 @@ result.throw();
|
|
|
144
145
|
console.log(result.output);
|
|
145
146
|
```
|
|
146
147
|
|
|
148
|
+
### Services
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const services = await notebook.services.list();
|
|
152
|
+
|
|
153
|
+
await notebook.services.run('redis');
|
|
154
|
+
|
|
155
|
+
const snapshot = await notebook.services.logs('redis', { tail: 50 });
|
|
156
|
+
console.log(snapshot);
|
|
157
|
+
|
|
158
|
+
const stream = notebook.services.logs('redis', { follow: true, tail: 25 });
|
|
159
|
+
const reader = stream.output.getReader();
|
|
160
|
+
const chunk = await reader.read();
|
|
161
|
+
console.log(chunk.value);
|
|
162
|
+
await stream.stop();
|
|
163
|
+
```
|
|
164
|
+
|
|
147
165
|
### Composer
|
|
148
166
|
|
|
149
167
|
```ts
|
|
@@ -572,6 +572,13 @@ var SendTimeoutError = class _SendTimeoutError extends PromiseTimeoutError {
|
|
|
572
572
|
return new _SendTimeoutError(error.message, error.time);
|
|
573
573
|
}
|
|
574
574
|
};
|
|
575
|
+
var NotebookUnavailableError = class extends Error {
|
|
576
|
+
constructor(message = "Notebook is no longer available", raw = {}) {
|
|
577
|
+
super(message);
|
|
578
|
+
this.raw = raw;
|
|
579
|
+
this.name = "NotebookUnavailableError";
|
|
580
|
+
}
|
|
581
|
+
};
|
|
575
582
|
|
|
576
583
|
// src/utils/promise.ts
|
|
577
584
|
var timeout = (prom, time) => {
|
|
@@ -1019,6 +1026,103 @@ var Shell = class {
|
|
|
1019
1026
|
}
|
|
1020
1027
|
};
|
|
1021
1028
|
|
|
1029
|
+
// src/services.ts
|
|
1030
|
+
var Services = class {
|
|
1031
|
+
constructor(okra) {
|
|
1032
|
+
this.okra = okra;
|
|
1033
|
+
}
|
|
1034
|
+
list() {
|
|
1035
|
+
return this.okra.invoke("service.list");
|
|
1036
|
+
}
|
|
1037
|
+
run(name) {
|
|
1038
|
+
return this.okra.invoke("service.run", { name });
|
|
1039
|
+
}
|
|
1040
|
+
stop(name) {
|
|
1041
|
+
return this.okra.invoke("service.stop", { name });
|
|
1042
|
+
}
|
|
1043
|
+
onLog(id, handler) {
|
|
1044
|
+
return this.okra.listen(`service.log.${id}`, handler);
|
|
1045
|
+
}
|
|
1046
|
+
listen(event, handler) {
|
|
1047
|
+
return this.okra.listen(event, handler);
|
|
1048
|
+
}
|
|
1049
|
+
logs(name, options = {}) {
|
|
1050
|
+
if (options.follow) {
|
|
1051
|
+
return this.followLogs(name, options);
|
|
1052
|
+
}
|
|
1053
|
+
return this.okra.invoke("service.logs", {
|
|
1054
|
+
name,
|
|
1055
|
+
tail: options.tail
|
|
1056
|
+
}).then((response) => {
|
|
1057
|
+
if (!("output" in response)) {
|
|
1058
|
+
throw new Error(`Unexpected service.logs response for ${name}`);
|
|
1059
|
+
}
|
|
1060
|
+
return response.output;
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
followLogs(name, options) {
|
|
1064
|
+
const id = options.id || nanoid();
|
|
1065
|
+
const disposables = /* @__PURE__ */ new Set();
|
|
1066
|
+
let controller = null;
|
|
1067
|
+
let closed = false;
|
|
1068
|
+
const dispose = () => {
|
|
1069
|
+
for (const disposable of disposables) {
|
|
1070
|
+
disposable.dispose();
|
|
1071
|
+
}
|
|
1072
|
+
disposables.clear();
|
|
1073
|
+
};
|
|
1074
|
+
const close = () => {
|
|
1075
|
+
if (closed) {
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
closed = true;
|
|
1079
|
+
dispose();
|
|
1080
|
+
if (controller) {
|
|
1081
|
+
try {
|
|
1082
|
+
controller.close();
|
|
1083
|
+
} catch {
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
const fail = (error) => {
|
|
1088
|
+
if (closed) {
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
closed = true;
|
|
1092
|
+
dispose();
|
|
1093
|
+
if (controller) {
|
|
1094
|
+
controller.error(error);
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
const stop = once(() => {
|
|
1098
|
+
close();
|
|
1099
|
+
return this.okra.invoke("service.stop-logs", { id });
|
|
1100
|
+
});
|
|
1101
|
+
const output = new ReadableStream({
|
|
1102
|
+
start: (_controller) => {
|
|
1103
|
+
controller = _controller;
|
|
1104
|
+
disposables.add(
|
|
1105
|
+
this.onLog(id, (data) => {
|
|
1106
|
+
controller?.enqueue(data.output);
|
|
1107
|
+
})
|
|
1108
|
+
);
|
|
1109
|
+
void this.okra.invoke("service.logs", {
|
|
1110
|
+
name,
|
|
1111
|
+
tail: options.tail,
|
|
1112
|
+
follow: true,
|
|
1113
|
+
id
|
|
1114
|
+
}).catch((error) => {
|
|
1115
|
+
fail(error);
|
|
1116
|
+
});
|
|
1117
|
+
},
|
|
1118
|
+
cancel: () => {
|
|
1119
|
+
void stop();
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
return { id, output, stop };
|
|
1123
|
+
}
|
|
1124
|
+
};
|
|
1125
|
+
|
|
1022
1126
|
// node_modules/@msgpack/msgpack/dist.esm/utils/utf8.mjs
|
|
1023
1127
|
function utf8Count(str) {
|
|
1024
1128
|
const strLength = str.length;
|
|
@@ -3042,6 +3146,7 @@ var Transport = class {
|
|
|
3042
3146
|
this.closed = false;
|
|
3043
3147
|
this.disposables = new NamedDisposable();
|
|
3044
3148
|
this.connectPromise = null;
|
|
3149
|
+
this.terminalError = null;
|
|
3045
3150
|
this.pingIntervalStarted = false;
|
|
3046
3151
|
// Connection health monitoring
|
|
3047
3152
|
this.connectionStats = {
|
|
@@ -3073,7 +3178,7 @@ var Transport = class {
|
|
|
3073
3178
|
const startClosed = options.startClosed !== false;
|
|
3074
3179
|
this.rws = new reconnecting_websocket_mjs_default(this.url.toString(), [], {
|
|
3075
3180
|
WebSocket: globalThis.WebSocket ?? browser_default,
|
|
3076
|
-
connectionTimeout: options.connectionTimeout
|
|
3181
|
+
connectionTimeout: options.connectionTimeout,
|
|
3077
3182
|
maxReconnectionDelay: 2e3,
|
|
3078
3183
|
minReconnectionDelay: 200,
|
|
3079
3184
|
maxEnqueuedMessages: 0,
|
|
@@ -3116,6 +3221,9 @@ var Transport = class {
|
|
|
3116
3221
|
* Ensure the websocket is open without requiring an application-level roundtrip.
|
|
3117
3222
|
*/
|
|
3118
3223
|
connect() {
|
|
3224
|
+
if (this.terminalError) {
|
|
3225
|
+
return Promise.reject(this.terminalError);
|
|
3226
|
+
}
|
|
3119
3227
|
return __privateMethod(this, _Transport_instances, connect_fn).call(this);
|
|
3120
3228
|
}
|
|
3121
3229
|
id() {
|
|
@@ -3172,7 +3280,12 @@ var Transport = class {
|
|
|
3172
3280
|
return;
|
|
3173
3281
|
}
|
|
3174
3282
|
if (event === "Events.BootError" /* BootError */) {
|
|
3283
|
+
const error = new NotebookUnavailableError(
|
|
3284
|
+
data?.message || "Notebook is no longer available",
|
|
3285
|
+
data || {}
|
|
3286
|
+
);
|
|
3175
3287
|
this.log("error", "Boot error received", { data });
|
|
3288
|
+
this.terminate(error, 4e3, error.message);
|
|
3176
3289
|
return;
|
|
3177
3290
|
}
|
|
3178
3291
|
if (event === "response" /* Response */) {
|
|
@@ -3231,6 +3344,11 @@ var Transport = class {
|
|
|
3231
3344
|
listen(event, listener, _context) {
|
|
3232
3345
|
return this.eventEmitter.listen(event, listener);
|
|
3233
3346
|
}
|
|
3347
|
+
onDidBootError(listener) {
|
|
3348
|
+
this.eventEmitter.listen("transport.boot_error", (event) => {
|
|
3349
|
+
listener(event.error);
|
|
3350
|
+
});
|
|
3351
|
+
}
|
|
3234
3352
|
removeListener(event, listener) {
|
|
3235
3353
|
this.eventEmitter.removeListener(event, listener);
|
|
3236
3354
|
}
|
|
@@ -3257,6 +3375,9 @@ var Transport = class {
|
|
|
3257
3375
|
get isClosed() {
|
|
3258
3376
|
return this.closed;
|
|
3259
3377
|
}
|
|
3378
|
+
getTerminalError() {
|
|
3379
|
+
return this.terminalError;
|
|
3380
|
+
}
|
|
3260
3381
|
get status() {
|
|
3261
3382
|
return {
|
|
3262
3383
|
0: "CONNECTING",
|
|
@@ -3266,6 +3387,9 @@ var Transport = class {
|
|
|
3266
3387
|
}[this.rws.readyState];
|
|
3267
3388
|
}
|
|
3268
3389
|
async call(action, data = {}, options = {}) {
|
|
3390
|
+
if (this.terminalError) {
|
|
3391
|
+
throw this.terminalError;
|
|
3392
|
+
}
|
|
3269
3393
|
if (this.isRateLimited()) {
|
|
3270
3394
|
throw new RateLimitError("Rate limit exceeded - too many requests");
|
|
3271
3395
|
}
|
|
@@ -3282,6 +3406,10 @@ var Transport = class {
|
|
|
3282
3406
|
this.eventEmitter.removeListener(errorEvent);
|
|
3283
3407
|
};
|
|
3284
3408
|
const handler = async (resolve, reject) => {
|
|
3409
|
+
if (this.terminalError) {
|
|
3410
|
+
reject(this.terminalError);
|
|
3411
|
+
return;
|
|
3412
|
+
}
|
|
3285
3413
|
const abortError = new DOMException("Request aborted", "AbortError");
|
|
3286
3414
|
if (options.abortSignal?.aborted) {
|
|
3287
3415
|
reject(abortError);
|
|
@@ -3333,7 +3461,7 @@ var Transport = class {
|
|
|
3333
3461
|
reject(new RateLimitError(_ev.reason || "Rate limit exceeded", _ev));
|
|
3334
3462
|
return;
|
|
3335
3463
|
}
|
|
3336
|
-
reject(new Error(`Connection lost to the notebook during request: ${_ev.reason || "Unknown reason"}`));
|
|
3464
|
+
reject(this.terminalError || new Error(`Connection lost to the notebook during request: ${_ev.reason || "Unknown reason"}`));
|
|
3337
3465
|
};
|
|
3338
3466
|
this.rws.addEventListener("close", closeHandler);
|
|
3339
3467
|
this.rws.addEventListener("error", closeHandler);
|
|
@@ -3369,7 +3497,7 @@ var Transport = class {
|
|
|
3369
3497
|
try {
|
|
3370
3498
|
return await sender();
|
|
3371
3499
|
} catch (e) {
|
|
3372
|
-
if (e instanceof ErrorEvent || e instanceof RateLimitError || e instanceof InvalidConfigurationError || e instanceof InvalidMessageError || e instanceof DOMException) {
|
|
3500
|
+
if (e instanceof ErrorEvent || e instanceof RateLimitError || e instanceof InvalidConfigurationError || e instanceof InvalidMessageError || e instanceof NotebookUnavailableError || e instanceof DOMException) {
|
|
3373
3501
|
this.log("debug", "Non-retryable error, bailing", {
|
|
3374
3502
|
error: e.message,
|
|
3375
3503
|
attempt
|
|
@@ -3421,6 +3549,9 @@ var Transport = class {
|
|
|
3421
3549
|
* This preserves all event listeners and state.
|
|
3422
3550
|
*/
|
|
3423
3551
|
reconnect() {
|
|
3552
|
+
if (this.terminalError) {
|
|
3553
|
+
throw this.terminalError;
|
|
3554
|
+
}
|
|
3424
3555
|
if (this.closed) {
|
|
3425
3556
|
throw new Error("Cannot reconnect a closed transport. The transport has been permanently closed.");
|
|
3426
3557
|
}
|
|
@@ -3435,6 +3566,16 @@ var Transport = class {
|
|
|
3435
3566
|
}
|
|
3436
3567
|
this.close();
|
|
3437
3568
|
}
|
|
3569
|
+
terminate(error, code = 4e3, reason = error.message) {
|
|
3570
|
+
this.terminalError = error;
|
|
3571
|
+
if (error instanceof NotebookUnavailableError) {
|
|
3572
|
+
this.eventEmitter.emit("transport.boot_error", {
|
|
3573
|
+
error,
|
|
3574
|
+
timestamp: Date.now()
|
|
3575
|
+
});
|
|
3576
|
+
}
|
|
3577
|
+
this.close(code, reason);
|
|
3578
|
+
}
|
|
3438
3579
|
close(code, reason) {
|
|
3439
3580
|
if (this.closed) {
|
|
3440
3581
|
return;
|
|
@@ -3442,9 +3583,9 @@ var Transport = class {
|
|
|
3442
3583
|
this.log("info", "Closing transport connection", { code, reason });
|
|
3443
3584
|
this.connectPromise = null;
|
|
3444
3585
|
const queuedCount = this.messageQueue.length;
|
|
3586
|
+
const closeError = this.terminalError || new Error("Connection closed while message was queued");
|
|
3445
3587
|
this.messageQueue.forEach((msg) => {
|
|
3446
|
-
|
|
3447
|
-
msg.reject(new Error("Connection closed while message was queued"));
|
|
3588
|
+
msg.reject(closeError);
|
|
3448
3589
|
});
|
|
3449
3590
|
this.messageQueue = [];
|
|
3450
3591
|
if (queuedCount > 0) {
|
|
@@ -3532,6 +3673,9 @@ var Transport = class {
|
|
|
3532
3673
|
this.log("error", "Connection closed due to policy violation");
|
|
3533
3674
|
this.clearOldQueuedMessages();
|
|
3534
3675
|
return "stop";
|
|
3676
|
+
case 4e3:
|
|
3677
|
+
this.log("info", "Connection closed due to terminal notebook error");
|
|
3678
|
+
return "stop";
|
|
3535
3679
|
default:
|
|
3536
3680
|
this.log("warn", `Unknown close code: ${code}, will reconnect`);
|
|
3537
3681
|
return "reconnect";
|
|
@@ -3747,6 +3891,9 @@ _Transport_instances = new WeakSet();
|
|
|
3747
3891
|
* by caching the connection promise.
|
|
3748
3892
|
*/
|
|
3749
3893
|
connect_fn = function() {
|
|
3894
|
+
if (this.terminalError) {
|
|
3895
|
+
return Promise.reject(this.terminalError);
|
|
3896
|
+
}
|
|
3750
3897
|
if (this.isConnected) {
|
|
3751
3898
|
return Promise.resolve();
|
|
3752
3899
|
}
|
|
@@ -4793,9 +4940,14 @@ var NotebookInstance = class {
|
|
|
4793
4940
|
this.laravel = new Lravel(this);
|
|
4794
4941
|
this.shell = new Shell(this);
|
|
4795
4942
|
this.git = new Git(this);
|
|
4943
|
+
this.services = new Services(this);
|
|
4796
4944
|
this.secrets = new NotebookSecrets(client, this.data.id);
|
|
4797
4945
|
}
|
|
4798
4946
|
async ready() {
|
|
4947
|
+
const terminalError = this.socket.getTerminalError();
|
|
4948
|
+
if (terminalError) {
|
|
4949
|
+
throw terminalError;
|
|
4950
|
+
}
|
|
4799
4951
|
const ready = async () => {
|
|
4800
4952
|
if (this.client.options.startClosed && !this.socket.isConnected) {
|
|
4801
4953
|
await this.socket.connect();
|
|
@@ -4808,7 +4960,9 @@ var NotebookInstance = class {
|
|
|
4808
4960
|
return this.client.notebook.fork(this.data.id);
|
|
4809
4961
|
}
|
|
4810
4962
|
delete() {
|
|
4811
|
-
return this.client.notebook.delete(this.data.id)
|
|
4963
|
+
return this.client.notebook.delete(this.data.id).then(() => {
|
|
4964
|
+
this.socket.terminate(new NotebookUnavailableError("Notebook has been deleted.", { id: this.data.id }));
|
|
4965
|
+
});
|
|
4812
4966
|
}
|
|
4813
4967
|
stop() {
|
|
4814
4968
|
return this.container.stop();
|
|
@@ -4832,6 +4986,10 @@ var NotebookInstance = class {
|
|
|
4832
4986
|
!this.socket.isClosed && this.socket.disconnect();
|
|
4833
4987
|
}
|
|
4834
4988
|
connected() {
|
|
4989
|
+
const terminalError = this.socket.getTerminalError();
|
|
4990
|
+
if (terminalError) {
|
|
4991
|
+
return Promise.reject(terminalError);
|
|
4992
|
+
}
|
|
4835
4993
|
if (this.socket.isConnected) {
|
|
4836
4994
|
return Promise.resolve(this);
|
|
4837
4995
|
}
|
|
@@ -4839,18 +4997,24 @@ var NotebookInstance = class {
|
|
|
4839
4997
|
try {
|
|
4840
4998
|
this.socket.onDidConnect(() => resolve(this));
|
|
4841
4999
|
this.socket.onDidClose(() => reject(new Error("Connection closed")));
|
|
5000
|
+
this.socket.onDidBootError((error) => reject(error));
|
|
4842
5001
|
} catch (e) {
|
|
4843
5002
|
reject(e);
|
|
4844
5003
|
}
|
|
4845
5004
|
});
|
|
4846
5005
|
}
|
|
4847
5006
|
whenConnected() {
|
|
5007
|
+
const terminalError = this.socket.getTerminalError();
|
|
5008
|
+
if (terminalError) {
|
|
5009
|
+
return Promise.reject(terminalError);
|
|
5010
|
+
}
|
|
4848
5011
|
if (this.socket.isConnected) {
|
|
4849
5012
|
return Promise.resolve(this);
|
|
4850
5013
|
}
|
|
4851
5014
|
return new Promise((resolve, reject) => {
|
|
4852
5015
|
try {
|
|
4853
5016
|
this.socket.onDidConnect(() => resolve(this));
|
|
5017
|
+
this.socket.onDidBootError((error) => reject(error));
|
|
4854
5018
|
} catch (e) {
|
|
4855
5019
|
reject(e);
|
|
4856
5020
|
}
|
|
@@ -4867,6 +5031,11 @@ var NotebookInstance = class {
|
|
|
4867
5031
|
this.socket.emit("okra.disconnected");
|
|
4868
5032
|
this.initialized = false;
|
|
4869
5033
|
});
|
|
5034
|
+
this.socket.onDidBootError((error) => {
|
|
5035
|
+
this.socket.emit("okra.boot_error", error);
|
|
5036
|
+
this.socket.emit("okra.disconnected");
|
|
5037
|
+
this.initialized = false;
|
|
5038
|
+
});
|
|
4870
5039
|
}
|
|
4871
5040
|
onDidConnect(handler) {
|
|
4872
5041
|
this.socket.removeListener("okra.connected", handler);
|
|
@@ -4879,6 +5048,11 @@ var NotebookInstance = class {
|
|
|
4879
5048
|
this.disposables.push(disposable);
|
|
4880
5049
|
return disposable;
|
|
4881
5050
|
}
|
|
5051
|
+
onDidBootError(handler) {
|
|
5052
|
+
const disposable = this.socket.listen("okra.boot_error", handler);
|
|
5053
|
+
this.disposables.push(disposable);
|
|
5054
|
+
return disposable;
|
|
5055
|
+
}
|
|
4882
5056
|
update() {
|
|
4883
5057
|
return this.invoke("notebook.update");
|
|
4884
5058
|
}
|
|
@@ -4904,6 +5078,7 @@ _NotebookInstance_instances = new WeakSet();
|
|
|
4904
5078
|
init_fn = function() {
|
|
4905
5079
|
__privateSet(this, _initPromise, new Promise((resolve, reject) => {
|
|
4906
5080
|
const initializationListener = this.onDidInitialize((result) => {
|
|
5081
|
+
bootErrorListener.dispose();
|
|
4907
5082
|
initializationListener.dispose();
|
|
4908
5083
|
this.initialized = result;
|
|
4909
5084
|
if (result.type === "error") {
|
|
@@ -4912,6 +5087,11 @@ init_fn = function() {
|
|
|
4912
5087
|
}
|
|
4913
5088
|
resolve(result);
|
|
4914
5089
|
});
|
|
5090
|
+
const bootErrorListener = this.onDidBootError((error) => {
|
|
5091
|
+
initializationListener.dispose();
|
|
5092
|
+
bootErrorListener.dispose();
|
|
5093
|
+
reject(error);
|
|
5094
|
+
});
|
|
4915
5095
|
}));
|
|
4916
5096
|
return __privateGet(this, _initPromise);
|
|
4917
5097
|
};
|
|
@@ -4955,6 +5135,7 @@ export {
|
|
|
4955
5135
|
NotebookSecretApi,
|
|
4956
5136
|
NotebookSecrets,
|
|
4957
5137
|
NotebookState,
|
|
5138
|
+
NotebookUnavailableError,
|
|
4958
5139
|
PHPSandbox,
|
|
4959
5140
|
PHPSandboxError,
|
|
4960
5141
|
PromiseTimeoutError,
|