@phpsandbox/sdk 0.1.1 → 0.1.2

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.
@@ -109,25 +109,119 @@ var Filesystem = class {
109
109
  }
110
110
  });
111
111
  }
112
- info(path) {
113
- return this.okra.invoke("fs.info", { path });
112
+ async write(path, contents, options = {}) {
113
+ const resolvedOptions = {
114
+ overwrite: true,
115
+ create: true,
116
+ unlock: false,
117
+ atomic: false,
118
+ ...options
119
+ };
120
+ const source = typeof contents === "string" ? new TextEncoder().encode(contents) : contents;
121
+ if (this.okra.runtimeTransport === "rest") {
122
+ const bytes = source instanceof Uint8Array ? source : await collectBytes(source);
123
+ await this.okra.invoke("fs.writeFile", {
124
+ path,
125
+ contents: bytes,
126
+ options: resolvedOptions
127
+ }).catch((error51) => this.handleError(error51));
128
+ return;
129
+ }
130
+ const id = nanoid();
131
+ const completion = this.okra.invoke("fs.writeStream", { id, path, options: resolvedOptions });
132
+ void completion.catch(() => {
133
+ });
134
+ try {
135
+ for await (const chunk of toAsyncIterable(source)) {
136
+ const written = await this.okra.invoke("fs.writeChunk", { id, contents: chunk });
137
+ if (!written) {
138
+ throw new Error(`File write stream ${id} is not available`);
139
+ }
140
+ }
141
+ const ended = await this.okra.invoke("fs.endWrite", { id });
142
+ if (!ended) {
143
+ throw new Error(`File write stream ${id} could not be completed`);
144
+ }
145
+ await completion;
146
+ } catch (error51) {
147
+ await this.okra.invoke("fs.abortWrite", { id }).catch(() => false);
148
+ await completion.catch(() => false);
149
+ throw error51;
150
+ }
114
151
  }
115
- async write(path, contents, options = { overwrite: true, create: true, unlock: false, atomic: false }) {
116
- if (typeof contents === "string") {
117
- return this.okra.invoke("fs.write", { path, contents });
152
+ async read(path) {
153
+ try {
154
+ const content = await this.okra.invoke("fs.readFile", { path });
155
+ return content instanceof Uint8Array ? content : new TextEncoder().encode(content);
156
+ } catch (error51) {
157
+ this.handleError(error51);
118
158
  }
119
- const bytes = contents instanceof Uint8Array ? contents : await collectBytes(contents);
120
- await this.writeFile(path, bytes, options);
121
- return true;
122
159
  }
123
- read(path) {
160
+ async readText(path) {
161
+ return new TextDecoder().decode(await this.read(path));
162
+ }
163
+ async readLines(path, range) {
164
+ try {
165
+ const result = await this.okra.invoke("fs.readFile", {
166
+ path,
167
+ lineRange: {
168
+ lineStart: range.start,
169
+ lineEnd: range.end
170
+ }
171
+ });
172
+ if (typeof result === "string" || result instanceof Uint8Array) {
173
+ throw new Error(`Unexpected ranged file response for ${path}`);
174
+ }
175
+ return {
176
+ start: result.lineStart,
177
+ end: result.lineEnd,
178
+ content: result.content,
179
+ ...result.error === null ? {} : { warning: result.error }
180
+ };
181
+ } catch (error51) {
182
+ this.handleError(error51);
183
+ }
184
+ }
185
+ readStream(path) {
186
+ if (this.okra.runtimeTransport === "rest") {
187
+ return new ReadableStream({
188
+ start: async (controller) => {
189
+ try {
190
+ controller.enqueue(await this.read(path));
191
+ controller.close();
192
+ } catch (error51) {
193
+ controller.error(error51);
194
+ }
195
+ }
196
+ });
197
+ }
198
+ const id = nanoid();
199
+ let disposable = null;
200
+ let closed = false;
124
201
  return new ReadableStream({
125
- start: async (controller) => {
126
- try {
127
- controller.enqueue(await this.readFile(path));
128
- controller.close();
129
- } catch (error51) {
130
- controller.error(error51);
202
+ start: (controller) => {
203
+ disposable = this.okra.listen(`fs.read.${id}`, (event) => {
204
+ controller.enqueue(event.data);
205
+ });
206
+ void this.okra.invoke("fs.readStream", { id, path }).then(() => {
207
+ if (!closed) {
208
+ closed = true;
209
+ disposable?.dispose();
210
+ controller.close();
211
+ }
212
+ }).catch((error51) => {
213
+ if (!closed) {
214
+ closed = true;
215
+ disposable?.dispose();
216
+ controller.error(error51);
217
+ }
218
+ });
219
+ },
220
+ cancel: async () => {
221
+ if (!closed) {
222
+ closed = true;
223
+ disposable?.dispose();
224
+ await this.okra.invoke("fs.cancelRead", { id }).catch(() => false);
131
225
  }
132
226
  }
133
227
  });
@@ -209,53 +303,38 @@ var Filesystem = class {
209
303
  const disposable = this.okra.listen(`fs.text.search.${sid}`, localOnMatch);
210
304
  return this.okra.invoke("fs.textSearch", { query, options: { ...defaultOptions, ...options } }).finally(() => disposable.dispose());
211
305
  }
212
- mkdir(path) {
213
- return this.okra.invoke("fs.mkdir", { path });
214
- }
215
- move(from, to) {
216
- return this.okra.invoke("fs.move", { from, to });
217
- }
218
- remove(path, type) {
219
- return this.okra.invoke("fs.remove", { path, type });
220
- }
221
- async readFile(path, lineRange) {
222
- try {
223
- const content = await this.okra.invoke("fs.readFile", { path, lineRange });
224
- if (content instanceof Uint8Array) {
225
- return content;
226
- }
227
- if (typeof content === "string") {
228
- return new TextEncoder().encode(content);
229
- }
230
- return content;
231
- } catch (e) {
232
- this.handleError(e);
233
- }
234
- }
235
- tail(path, lines = 10) {
236
- return this.okra.invoke("fs.tail", { path, lines }).catch((e) => this.handleError(e));
237
- }
238
- writeFile(path, contents, options) {
239
- return this.okra.invoke("fs.writeFile", {
240
- path,
241
- contents,
242
- options
243
- }).catch((e) => this.handleError(e));
306
+ tail(path, options = {}) {
307
+ return this.okra.invoke("fs.tail", { path, lines: options.lines ?? 10 }).catch((e) => this.handleError(e));
244
308
  }
245
309
  stat(path) {
246
310
  return this.okra.invoke("fs.stat", { path }).catch((e) => this.handleError(e));
247
311
  }
248
- rename(from, to, options) {
249
- return this.okra.invoke("fs.rename", { from, to, options }).catch((e) => this.handleError(e));
312
+ move(from, to, options = {}) {
313
+ return this.okra.invoke("fs.rename", {
314
+ from,
315
+ to,
316
+ options: { overwrite: false, ...options }
317
+ }).catch((e) => this.handleError(e));
250
318
  }
251
- delete(path, options) {
252
- return this.okra.invoke("fs.delete", { path, options }).catch((e) => this.handleError(e));
319
+ remove(path, options = {}) {
320
+ return this.okra.invoke("fs.delete", {
321
+ path,
322
+ options: { recursive: false, useTrash: false, atomic: false, ...options }
323
+ }).catch((e) => this.handleError(e));
253
324
  }
254
- copy(source, destination, options) {
255
- return this.okra.invoke("fs.copy", { source, destination, options }).catch((e) => this.handleError(e));
325
+ copy(source, destination, options = {}) {
326
+ return this.okra.invoke("fs.copy", {
327
+ source,
328
+ destination,
329
+ options: { overwrite: false, ...options }
330
+ }).catch((e) => this.handleError(e));
256
331
  }
257
- readDirectory(path, include = [], exclude = []) {
258
- return this.okra.invoke("fs.readDirectory", { path, include, exclude }).catch((e) => this.handleError(e));
332
+ list(path, options = {}) {
333
+ return this.okra.invoke("fs.readDirectory", {
334
+ path,
335
+ include: options.include ?? [],
336
+ exclude: options.exclude ?? []
337
+ }).catch((e) => this.handleError(e));
259
338
  }
260
339
  createDirectory(path) {
261
340
  return this.okra.invoke("fs.createDirectory", { path }).catch((e) => this.handleError(e));
@@ -284,17 +363,17 @@ var Filesystem = class {
284
363
  exists(path) {
285
364
  return this.stat(path).then(() => true).catch(() => false);
286
365
  }
287
- async download(chunk, exclude, include) {
366
+ async download(options = {}) {
288
367
  const id = nanoid();
289
- const stream = !!chunk;
368
+ const stream = !!options.onChunk;
290
369
  const chunks = [];
291
370
  const disposable = this.okra.listen(
292
371
  `fs.download.${id}`,
293
- stream ? chunk : (data) => {
372
+ stream ? options.onChunk : (data) => {
294
373
  chunks.push(data);
295
374
  }
296
375
  );
297
- return this.okra.invoke("fs.download", { id, exclude, include }).then(() => new Blob(chunks, { type: "application/octet-stream" })).finally(() => disposable.dispose());
376
+ return this.okra.invoke("fs.download", { id, exclude: options.exclude, include: options.include }).then(() => new Blob(chunks, { type: "application/octet-stream" })).finally(() => disposable.dispose());
298
377
  }
299
378
  tree(path = "/") {
300
379
  return this.okra.invoke("fs.tree", { path });
@@ -306,6 +385,13 @@ var Filesystem = class {
306
385
  throw e;
307
386
  }
308
387
  };
388
+ async function* toAsyncIterable(contents) {
389
+ if (contents instanceof Uint8Array) {
390
+ yield contents;
391
+ return;
392
+ }
393
+ yield* contents;
394
+ }
309
395
  async function collectBytes(stream) {
310
396
  const chunks = [];
311
397
  let length = 0;
@@ -366,30 +452,35 @@ var once = (fn) => {
366
452
  // src/terminal.ts
367
453
  var TERMINAL_INPUT_FLUSH_DELAY_MS = 8;
368
454
  var terminalInputFlushPattern = /[\x00-\x1f\x7f]/;
369
- var Terminal = class {
455
+ var Terminals = class {
370
456
  constructor(okra) {
371
457
  this.okra = okra;
372
458
  }
373
459
  list() {
374
460
  return this.okra.invoke("terminal.list");
375
461
  }
376
- create(input) {
377
- return this.okra.invoke("terminal.create", input);
378
- }
379
- onStarted(handler) {
380
- return this.okra.listen("terminal.started", handler);
381
- }
382
- resize(id, size) {
383
- return this.okra.invoke("terminal.resize", { id, width: size[0], height: size[1] });
384
- }
385
- onOutput(id, handler) {
386
- return this.okra.listen(`terminal.output.${id}`, handler);
387
- }
388
- input(id, input) {
389
- return Promise.resolve(this.okra.send("terminal.input", { id, input }));
390
- }
391
- listen(event, handler) {
392
- return this.okra.listen(event, handler);
462
+ async create(options = {}) {
463
+ const id = options.id ?? nanoid();
464
+ const handle = this.processHandle(id, options.abortSignal);
465
+ const command = typeof options.command === "string" && options.args?.length ? [options.command, ...options.args] : options.command;
466
+ const { abortSignal, args: _args, ...input } = options;
467
+ try {
468
+ const task = await this.okra.invoke(
469
+ "terminal.create",
470
+ {
471
+ ...input,
472
+ id,
473
+ kind: options.kind ?? "bash",
474
+ size: options.size ?? [80, 24],
475
+ command
476
+ },
477
+ { abortSignal }
478
+ );
479
+ return { ...handle.process, ...task };
480
+ } catch (error51) {
481
+ handle.dispose();
482
+ throw error51;
483
+ }
393
484
  }
394
485
  async attach(id, opts) {
395
486
  const handle = this.processHandle(id, opts?.abortSignal);
@@ -415,31 +506,6 @@ var Terminal = class {
415
506
  throw error51;
416
507
  }
417
508
  }
418
- async spawn(command, args, opts) {
419
- const id = opts?.id || nanoid();
420
- const handle = this.processHandle(id, opts?.abortSignal);
421
- const { abortSignal, ...otherOpts } = opts ?? {};
422
- try {
423
- const result = await this.okra.invoke(
424
- "terminal.spawn",
425
- {
426
- command: [command, ...args],
427
- opts: {
428
- id,
429
- ...otherOpts
430
- }
431
- },
432
- { abortSignal }
433
- );
434
- return {
435
- ...handle.process,
436
- ...result
437
- };
438
- } catch (error51) {
439
- handle.dispose();
440
- throw error51;
441
- }
442
- }
443
509
  processHandle(id, abortSignal) {
444
510
  const disposables = /* @__PURE__ */ new Set();
445
511
  let abortHandler;
@@ -465,7 +531,7 @@ var Terminal = class {
465
531
  }
466
532
  const input2 = pendingInput;
467
533
  pendingInput = "";
468
- void this.input(id, input2);
534
+ void this.okra.send("terminal.input", { id, input: input2 });
469
535
  };
470
536
  const scheduleInputFlush = () => {
471
537
  if (inputFlushTimer) {
@@ -473,7 +539,8 @@ var Terminal = class {
473
539
  }
474
540
  inputFlushTimer = setTimeout(flushInput, TERMINAL_INPUT_FLUSH_DELAY_MS);
475
541
  };
476
- const queueInput = (chunk) => {
542
+ const queueInput = (value) => {
543
+ const chunk = typeof value === "string" ? value : new TextDecoder().decode(value);
477
544
  pendingInput += chunk;
478
545
  if (terminalInputFlushPattern.test(chunk)) {
479
546
  flushInput();
@@ -495,7 +562,7 @@ var Terminal = class {
495
562
  start: (_controller) => {
496
563
  controller = _controller;
497
564
  disposables.add(
498
- this.listen(`terminal.output.${id}`, (data) => {
565
+ this.okra.listen(`terminal.output.${id}`, (data) => {
499
566
  controller?.enqueue(data.output);
500
567
  })
501
568
  );
@@ -507,7 +574,7 @@ var Terminal = class {
507
574
  });
508
575
  const completion = new Promise((resolve) => {
509
576
  disposables.add(
510
- this.listen(`terminal.close.${id}`, (data) => {
577
+ this.okra.listen(`terminal.close.${id}`, (data) => {
511
578
  if (controller) {
512
579
  try {
513
580
  controller.close();
@@ -572,37 +639,9 @@ var Container = class {
572
639
  state() {
573
640
  return this.okra.invoke("container.state");
574
641
  }
575
- openedPorts() {
576
- return this.okra.invoke("container.opened-ports");
577
- }
578
642
  setPhp(version2) {
579
643
  return this.okra.invoke("container.set-php", { version: version2 });
580
644
  }
581
- enableTelemetry(features) {
582
- return this.okra.invoke("container.stream-telemetry", { features: Array.from(features) });
583
- }
584
- stopTelemetry() {
585
- return this.okra.invoke("container.stop-telemetry");
586
- }
587
- listen(event, handler) {
588
- return this.okra.listen(event, handler);
589
- }
590
- onPort(handler) {
591
- let ports = [];
592
- return this.listen("container.ports", (newPorts) => {
593
- for (const port of newPorts) {
594
- if (!ports.some((p) => p.port === port.port)) {
595
- handler(port, "open");
596
- }
597
- }
598
- for (const port of ports) {
599
- if (!newPorts.some((p) => p.port === port.port)) {
600
- handler(port, "close");
601
- }
602
- }
603
- ports = newPorts;
604
- });
605
- }
606
645
  };
607
646
 
608
647
  // src/auth.ts
@@ -689,76 +728,6 @@ var LspConnection = class _LspConnection {
689
728
  }
690
729
  };
691
730
 
692
- // src/composer.ts
693
- var Composer = class {
694
- constructor(okra, client) {
695
- this.okra = okra;
696
- this.credentials = new ComposerCredentials(client, okra.data.id);
697
- }
698
- invoke(command, args = {}, options = {}) {
699
- return this.okra.invoke("composer.invoke", { command, args, options });
700
- }
701
- dumpAutoload() {
702
- return this.okra.invoke("composer.dump-autoload");
703
- }
704
- install(options = {}) {
705
- return this.invoke("install", {}, options);
706
- }
707
- update(args, options = {}) {
708
- return this.invoke("update", args, options);
709
- }
710
- require(packages, options = {}) {
711
- return this.invoke("require", packages, options);
712
- }
713
- remove(args, options = {}) {
714
- return this.invoke("remove", args, options);
715
- }
716
- stream(fn) {
717
- return this.okra.listen("composer.log", fn);
718
- }
719
- packages() {
720
- return this.okra.invoke("composer.packages");
721
- }
722
- };
723
-
724
- // src/log.ts
725
- var Log = class {
726
- constructor(okra) {
727
- this.okra = okra;
728
- }
729
- stream(fn) {
730
- return this.okra.listen("notebook.log", fn);
731
- }
732
- listen(event, handler) {
733
- return this.okra.listen(event, handler);
734
- }
735
- };
736
-
737
- // src/repl.ts
738
- var Repl = class {
739
- constructor(okra) {
740
- this.okra = okra;
741
- }
742
- eval(code, args = "", repl = { prependWith: "", appendWith: "" }) {
743
- return this.okra.invoke("repl.eval", { code, args, repl });
744
- }
745
- write(input) {
746
- return this.okra.invoke("repl.write", { input });
747
- }
748
- stop() {
749
- return this.okra.invoke("repl.stop");
750
- }
751
- resize(cols, rows) {
752
- return this.okra.invoke("repl.resize", { cols, rows });
753
- }
754
- listen(event, handler) {
755
- return this.okra.listen(event, handler);
756
- }
757
- onOutput(handler) {
758
- return this.okra.listen("repl.output", handler);
759
- }
760
- };
761
-
762
731
  // src/shell.ts
763
732
  function resolveRunInput(command, argsOrOpts = [], opts) {
764
733
  const args = Array.isArray(argsOrOpts) ? argsOrOpts : [];
@@ -788,7 +757,7 @@ var ProcessResult = class {
788
757
  return this;
789
758
  }
790
759
  };
791
- var OutputStream = class {
760
+ var ProcessReadable = class {
792
761
  constructor() {
793
762
  this.controller = null;
794
763
  this.closed = false;
@@ -828,9 +797,9 @@ var ShellProcess = class {
828
797
  constructor(id, okra, command, opts) {
829
798
  this.id = id;
830
799
  this.okra = okra;
831
- const output = new OutputStream();
832
- const stdout = new OutputStream();
833
- const stderr = new OutputStream();
800
+ const output = new ProcessReadable();
801
+ const stdout = new ProcessReadable();
802
+ const stderr = new ProcessReadable();
834
803
  this.output = output.stream;
835
804
  this.stdout = stdout.stream;
836
805
  this.stderr = stderr.stream;
@@ -899,6 +868,264 @@ var Shell = class {
899
868
  }
900
869
  };
901
870
 
871
+ // src/composer.ts
872
+ var ComposerProcess = class {
873
+ constructor(id, okra, command, args, options) {
874
+ this.id = id;
875
+ this.okra = okra;
876
+ const output = new ProcessReadable();
877
+ const stdout = new ProcessReadable();
878
+ const stderr = new ProcessReadable();
879
+ this.output = output.stream;
880
+ this.stdout = stdout.stream;
881
+ this.stderr = stderr.stream;
882
+ const encoder = new TextEncoder();
883
+ let subscription = this.okra.listen(`composer.output.${this.id}`, (event) => {
884
+ const data = encoder.encode(event.output);
885
+ const source = event.source ?? "output";
886
+ output.enqueue({ source, data });
887
+ if (source === "stderr") {
888
+ stderr.enqueue(data);
889
+ } else {
890
+ stdout.enqueue(data);
891
+ }
892
+ });
893
+ const finish = () => {
894
+ subscription?.dispose();
895
+ subscription = null;
896
+ output.close();
897
+ stdout.close();
898
+ stderr.close();
899
+ };
900
+ const fail = (error51) => {
901
+ subscription?.dispose();
902
+ subscription = null;
903
+ output.fail(error51);
904
+ stdout.fail(error51);
905
+ stderr.fail(error51);
906
+ };
907
+ this.completion = this.okra.invoke("composer.invoke", { id, command, args, options }).then((result) => {
908
+ finish();
909
+ return new ProcessResult(result.output, result.stdout, result.stderr, result.exitCode);
910
+ }).catch((error51) => {
911
+ fail(error51);
912
+ throw error51;
913
+ });
914
+ }
915
+ wait() {
916
+ return this.completion;
917
+ }
918
+ async kill() {
919
+ await this.okra.invoke("composer.kill", { id: this.id });
920
+ }
921
+ };
922
+ var Composer = class {
923
+ constructor(okra, client) {
924
+ this.okra = okra;
925
+ this.credentials = new ComposerCredentials(client, okra.data.id);
926
+ }
927
+ run(command, args = {}, options = {}) {
928
+ return new ComposerProcess(nanoid(), this.okra, command, args, options);
929
+ }
930
+ dumpAutoload(options = {}) {
931
+ return this.run("dump-autoload", {}, options);
932
+ }
933
+ install(options = {}) {
934
+ return this.run("install", {}, options);
935
+ }
936
+ update(args, options = {}) {
937
+ return this.run("update", args, options);
938
+ }
939
+ require(packages, options = {}) {
940
+ return this.run("require", packages, options);
941
+ }
942
+ remove(args, options = {}) {
943
+ return this.run("remove", args, options);
944
+ }
945
+ packages() {
946
+ return this.okra.invoke("composer.packages");
947
+ }
948
+ };
949
+
950
+ // src/runtime-telemetry.ts
951
+ var RuntimeTelemetry = class {
952
+ constructor(okra) {
953
+ this.okra = okra;
954
+ this.references = /* @__PURE__ */ new Map();
955
+ this.synchronization = Promise.resolve();
956
+ if (okra.runtimeTransport === "realtime") {
957
+ okra.onDidConnect(() => {
958
+ if (this.references.size > 0) {
959
+ void this.synchronize();
960
+ }
961
+ });
962
+ }
963
+ }
964
+ async acquire(feature) {
965
+ this.references.set(feature, (this.references.get(feature) ?? 0) + 1);
966
+ try {
967
+ await this.synchronize();
968
+ } catch (error51) {
969
+ this.removeReference(feature);
970
+ throw error51;
971
+ }
972
+ let released = false;
973
+ return async () => {
974
+ if (released) {
975
+ return;
976
+ }
977
+ released = true;
978
+ this.removeReference(feature);
979
+ await this.synchronize();
980
+ };
981
+ }
982
+ removeReference(feature) {
983
+ const references = this.references.get(feature) ?? 0;
984
+ if (references <= 1) {
985
+ this.references.delete(feature);
986
+ } else {
987
+ this.references.set(feature, references - 1);
988
+ }
989
+ }
990
+ synchronize() {
991
+ this.synchronization = this.synchronization.catch(() => {
992
+ }).then(async () => {
993
+ const features = Array.from(this.references.keys());
994
+ if (features.length === 0) {
995
+ await this.okra.invoke("container.stop-telemetry");
996
+ } else {
997
+ await this.okra.invoke("container.stream-telemetry", { features });
998
+ }
999
+ });
1000
+ return this.synchronization;
1001
+ }
1002
+ };
1003
+ function watchRuntimeTelemetry(okra, telemetry, feature, event, transform2, options = {}) {
1004
+ let subscription = null;
1005
+ let release = null;
1006
+ let closed = false;
1007
+ let abort = null;
1008
+ const stop = async () => {
1009
+ if (closed) {
1010
+ return;
1011
+ }
1012
+ closed = true;
1013
+ subscription?.dispose();
1014
+ subscription = null;
1015
+ if (abort && options.signal) {
1016
+ options.signal.removeEventListener("abort", abort);
1017
+ }
1018
+ abort = null;
1019
+ await release?.();
1020
+ release = null;
1021
+ };
1022
+ return new ReadableStream({
1023
+ start(controller) {
1024
+ subscription = okra.listen(event, (data) => {
1025
+ if (!closed) {
1026
+ controller.enqueue(transform2(data));
1027
+ }
1028
+ });
1029
+ if (options.signal) {
1030
+ abort = () => {
1031
+ void stop().finally(() => controller.error(options.signal?.reason ?? new Error("Aborted")));
1032
+ };
1033
+ if (options.signal.aborted) {
1034
+ abort();
1035
+ return;
1036
+ }
1037
+ options.signal.addEventListener("abort", abort, { once: true });
1038
+ }
1039
+ void telemetry.acquire(feature).then(async (releaseTelemetry) => {
1040
+ if (closed) {
1041
+ await releaseTelemetry();
1042
+ return;
1043
+ }
1044
+ release = releaseTelemetry;
1045
+ }).catch((error51) => {
1046
+ if (!closed) {
1047
+ closed = true;
1048
+ subscription?.dispose();
1049
+ if (abort && options.signal) {
1050
+ options.signal.removeEventListener("abort", abort);
1051
+ }
1052
+ abort = null;
1053
+ controller.error(error51);
1054
+ }
1055
+ });
1056
+ },
1057
+ cancel: stop
1058
+ });
1059
+ }
1060
+
1061
+ // src/log.ts
1062
+ var Logs = class {
1063
+ constructor(okra, telemetry) {
1064
+ this.okra = okra;
1065
+ this.telemetry = telemetry;
1066
+ }
1067
+ follow(options = {}) {
1068
+ return watchRuntimeTelemetry(this.okra, this.telemetry, "logs", "notebook.log", (message) => ({
1069
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1070
+ source: "runtime",
1071
+ message
1072
+ }), options);
1073
+ }
1074
+ };
1075
+
1076
+ // src/metrics.ts
1077
+ var Metrics = class {
1078
+ constructor(okra, telemetry) {
1079
+ this.okra = okra;
1080
+ this.telemetry = telemetry;
1081
+ }
1082
+ current() {
1083
+ return this.okra.invoke("container.stats");
1084
+ }
1085
+ watch(options = {}) {
1086
+ return watchRuntimeTelemetry(this.okra, this.telemetry, "stats", "container.stats", (stats) => stats, options);
1087
+ }
1088
+ };
1089
+
1090
+ // src/ports.ts
1091
+ var Ports = class {
1092
+ constructor(okra, telemetry) {
1093
+ this.okra = okra;
1094
+ this.telemetry = telemetry;
1095
+ }
1096
+ list() {
1097
+ return this.okra.invoke("container.opened-ports");
1098
+ }
1099
+ watch(options = {}) {
1100
+ return watchRuntimeTelemetry(this.okra, this.telemetry, "ports", "container.ports", (ports) => ports, options);
1101
+ }
1102
+ };
1103
+
1104
+ // src/repl.ts
1105
+ var Repl = class {
1106
+ constructor(okra) {
1107
+ this.okra = okra;
1108
+ }
1109
+ eval(code, args = "", repl = { prependWith: "", appendWith: "" }) {
1110
+ return this.okra.invoke("repl.eval", { code, args, repl });
1111
+ }
1112
+ write(input) {
1113
+ return this.okra.invoke("repl.write", { input });
1114
+ }
1115
+ stop() {
1116
+ return this.okra.invoke("repl.stop");
1117
+ }
1118
+ resize(cols, rows) {
1119
+ return this.okra.invoke("repl.resize", { cols, rows });
1120
+ }
1121
+ listen(event, handler) {
1122
+ return this.okra.listen(event, handler);
1123
+ }
1124
+ onOutput(handler) {
1125
+ return this.okra.listen("repl.output", handler);
1126
+ }
1127
+ };
1128
+
902
1129
  // src/services.ts
903
1130
  var notebookBuiltinServices = ["redis"];
904
1131
  var notebookKnownServices = ["start", "nginx", ...notebookBuiltinServices];
@@ -918,12 +1145,6 @@ var Services = class {
918
1145
  stop(name) {
919
1146
  return this.okra.invoke("service.stop", { name });
920
1147
  }
921
- onLog(id, handler) {
922
- return this.okra.listen(`service.log.${id}`, handler);
923
- }
924
- listen(event, handler) {
925
- return this.okra.listen(event, handler);
926
- }
927
1148
  logs(name, options = {}) {
928
1149
  if (options.follow) {
929
1150
  return this.followLogs(name, options);
@@ -976,11 +1197,11 @@ var Services = class {
976
1197
  close();
977
1198
  return this.okra.invoke("service.stop-logs", { id });
978
1199
  });
979
- const output = new ReadableStream({
1200
+ return new ReadableStream({
980
1201
  start: (_controller) => {
981
1202
  controller = _controller;
982
1203
  disposables.add(
983
- this.onLog(id, (data) => {
1204
+ this.okra.listen(`service.log.${id}`, (data) => {
984
1205
  controller?.enqueue(data.output);
985
1206
  })
986
1207
  );
@@ -994,10 +1215,9 @@ var Services = class {
994
1215
  });
995
1216
  },
996
1217
  cancel: () => {
997
- void stop();
1218
+ return stop().then(() => void 0);
998
1219
  }
999
1220
  });
1000
- return { id, output, stop };
1001
1221
  }
1002
1222
  };
1003
1223
 
@@ -19125,6 +19345,7 @@ var restActionRoutes = {
19125
19345
  "container.stop": { method: "POST", path: "/runtime/container/stop" },
19126
19346
  "container.set-php": { method: "PUT", path: "/runtime/container/php" },
19127
19347
  "container.opened-ports": { method: "GET", path: "/runtime/container/ports" },
19348
+ "container.stats": { method: "GET", path: "/runtime/container/stats" },
19128
19349
  "terminal.list": { method: "GET", path: "/runtime/terminals" },
19129
19350
  "shell.exec": { method: "POST", path: "/runtime/executions" },
19130
19351
  "fs.info": { method: "POST", path: "/runtime/files/info" },
@@ -19150,10 +19371,6 @@ var restActionRoutes = {
19150
19371
  "service.logs": { method: "POST", path: "/runtime/services/logs" },
19151
19372
  "composer.invoke": { method: "POST", path: "/runtime/composer/executions" },
19152
19373
  "composer.packages": { method: "GET", path: "/runtime/composer/packages" },
19153
- "composer.dump-autoload": {
19154
- method: "POST",
19155
- path: "/runtime/composer/autoload"
19156
- },
19157
19374
  "git.checkpoint": { method: "POST", path: "/runtime/git/checkpoints" },
19158
19375
  "git.checkout": { method: "POST", path: "/runtime/git/checkouts" },
19159
19376
  "git.log": { method: "POST", path: "/runtime/git/log" },
@@ -19397,7 +19614,7 @@ var NotebookApi = class {
19397
19614
  }
19398
19615
  async create(template, input = {}, init = true) {
19399
19616
  const response = await this.client.post("/notebook", { template, ...input });
19400
- const instance = new NotebookInstance2(response.data, this.client);
19617
+ const instance = new NotebookInstance(response.data, this.client);
19401
19618
  if (!init) {
19402
19619
  return instance;
19403
19620
  }
@@ -19405,25 +19622,25 @@ var NotebookApi = class {
19405
19622
  }
19406
19623
  async get(id) {
19407
19624
  const response = await this.client.get(`/notebook/${id}`);
19408
- return new NotebookInstance2(response.data, this.client);
19625
+ return new NotebookInstance(response.data, this.client);
19409
19626
  }
19410
19627
  async update(id, input = {}) {
19411
19628
  const response = await this.client.put(`/notebook/${id}`, input);
19412
- return new NotebookInstance2(response.data, this.client);
19629
+ return new NotebookInstance(response.data, this.client);
19413
19630
  }
19414
19631
  async destroy(id) {
19415
19632
  await this.client.delete(`/notebook/${id}`);
19416
19633
  }
19417
19634
  async fork(id, input = {}) {
19418
19635
  const response = await this.client.post(`/notebook/${id}/fork`, input);
19419
- return new NotebookInstance2(response.data, this.client);
19636
+ return new NotebookInstance(response.data, this.client);
19420
19637
  }
19421
19638
  async gitCredentials(id) {
19422
19639
  const response = await this.client.post(`/notebook/${id}/git/credentials`);
19423
19640
  return response.data;
19424
19641
  }
19425
19642
  openFromData(data) {
19426
- return this.init(new NotebookInstance2(data, this.client));
19643
+ return this.init(new NotebookInstance(data, this.client));
19427
19644
  }
19428
19645
  async init(instance) {
19429
19646
  await instance.ready();
@@ -19438,7 +19655,7 @@ function normalizeApiBaseUrl(url2) {
19438
19655
  baseUrl.hash = "";
19439
19656
  return baseUrl.toString();
19440
19657
  }
19441
- var Client2 = class {
19658
+ var Client = class {
19442
19659
  constructor(token, url2 = "https://api.phpsandbox.io/v1", options = {}) {
19443
19660
  this.runtimeTransportValue = "realtime";
19444
19661
  this.fetch = globalThis.fetch;
@@ -19522,7 +19739,7 @@ var Client2 = class {
19522
19739
  return { data: body === "" ? void 0 : JSON.parse(body) };
19523
19740
  }
19524
19741
  };
19525
- var PHPSandbox = class _PHPSandbox extends Client2 {
19742
+ var PHPSandbox = class _PHPSandbox extends Client {
19526
19743
  static realtime(token, url2 = "https://api.phpsandbox.io/v1", options = {}) {
19527
19744
  return new _PHPSandbox(token, url2, options);
19528
19745
  }
@@ -19630,7 +19847,7 @@ var NotebookMailApi = class {
19630
19847
  }
19631
19848
  };
19632
19849
  var _initPromise, _NotebookInstance_instances, init_fn;
19633
- var NotebookInstance2 = class {
19850
+ var NotebookInstance = class {
19634
19851
  constructor(data, client) {
19635
19852
  this.data = data;
19636
19853
  this.client = client;
@@ -19665,15 +19882,18 @@ var NotebookInstance2 = class {
19665
19882
  this.watchConnection();
19666
19883
  __privateSet(this, _initPromise, __privateMethod(this, _NotebookInstance_instances, init_fn).call(this));
19667
19884
  }
19668
- this.file = new Filesystem(
19885
+ this.files = new Filesystem(
19669
19886
  this,
19670
19887
  this.socket === null ? null : (handler) => this.onDidConnect(handler)
19671
19888
  );
19672
- this.terminal = new Terminal(this);
19889
+ this.terminals = new Terminals(this);
19673
19890
  this.auth = new Auth(this);
19674
19891
  this.lsp = new Lsp(this);
19675
19892
  this.composer = new Composer(this, client);
19676
- this.log = new Log(this);
19893
+ const telemetry = new RuntimeTelemetry(this);
19894
+ this.logs = new Logs(this, telemetry);
19895
+ this.metrics = new Metrics(this, telemetry);
19896
+ this.ports = new Ports(this, telemetry);
19677
19897
  this.repl = new Repl(this);
19678
19898
  this.container = new Container(this);
19679
19899
  this.shell = new Shell(this);
@@ -19719,6 +19939,12 @@ var NotebookInstance2 = class {
19719
19939
  }
19720
19940
  return this.shell.run(command, argsOrOpts);
19721
19941
  }
19942
+ exec(command, argsOrOpts = [], opts) {
19943
+ if (Array.isArray(argsOrOpts)) {
19944
+ return this.run(command, argsOrOpts, opts).wait();
19945
+ }
19946
+ return this.run(command, argsOrOpts).wait();
19947
+ }
19722
19948
  gitCredentials() {
19723
19949
  return this.client.notebook.gitCredentials(this.data.id);
19724
19950
  }
@@ -19809,9 +20035,6 @@ var NotebookInstance2 = class {
19809
20035
  const socket = this.realtimeSocket();
19810
20036
  socket.onDidConnect(() => {
19811
20037
  socket.emit("okra.connected");
19812
- if (this.client.options.telemetry) {
19813
- this.container.enableTelemetry(this.client.options.telemetry);
19814
- }
19815
20038
  });
19816
20039
  socket.onDidClose(() => {
19817
20040
  socket.emit("okra.disconnected");
@@ -19988,7 +20211,7 @@ function formatQueryString(params) {
19988
20211
  }
19989
20212
  export {
19990
20213
  ApiError,
19991
- Client2 as Client,
20214
+ Client,
19992
20215
  CommandError,
19993
20216
  ComposerCredentials,
19994
20217
  ErrorEvent,
@@ -20002,7 +20225,7 @@ export {
20002
20225
  NotebookApi,
20003
20226
  NotebookComposerCredentialApi,
20004
20227
  NotebookInitError,
20005
- NotebookInstance2 as NotebookInstance,
20228
+ NotebookInstance,
20006
20229
  NotebookMail,
20007
20230
  NotebookMailApi,
20008
20231
  NotebookPreview,
@@ -20014,6 +20237,7 @@ export {
20014
20237
  NotebookUnavailableError,
20015
20238
  PHPSandbox,
20016
20239
  PHPSandboxError,
20240
+ ProcessReadable,
20017
20241
  ProcessResult,
20018
20242
  PromiseTimeoutError,
20019
20243
  PublicationApi,
@@ -20048,6 +20272,7 @@ export {
20048
20272
  PublishStreamSsePhaseEventSchema,
20049
20273
  PublishStreamSseResultEventSchema,
20050
20274
  RateLimitError,
20275
+ RuntimeTelemetry,
20051
20276
  SendTimeoutError,
20052
20277
  ServerApi,
20053
20278
  ServerInstance,
@@ -20056,7 +20281,8 @@ export {
20056
20281
  notebookBuiltinServices,
20057
20282
  notebookKnownServices,
20058
20283
  once,
20059
- timeout
20284
+ timeout,
20285
+ watchRuntimeTelemetry
20060
20286
  };
20061
20287
  /*! Bundled license information:
20062
20288