@phpsandbox/sdk 0.1.1 → 0.1.4
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 +59 -22
- package/dist/browser/phpsandbox-sdk.esm.js +562 -265
- package/dist/browser/phpsandbox-sdk.esm.min.js +24 -24
- package/dist/browser/phpsandbox-sdk.iife.js +562 -265
- package/dist/browser/phpsandbox-sdk.iife.min.js +24 -24
- package/dist/composer.d.ts +36 -23
- package/dist/composer.js +61 -11
- package/dist/container.d.ts +2 -6
- package/dist/container.js +0 -28
- package/dist/filesystem.d.ts +74 -18
- package/dist/filesystem.js +219 -62
- package/dist/index.d.ts +18 -9
- package/dist/index.js +21 -8
- package/dist/log.d.ts +11 -5
- package/dist/log.js +10 -7
- package/dist/metrics.d.ts +10 -0
- package/dist/metrics.js +13 -0
- package/dist/ports.d.ts +10 -0
- package/dist/ports.js +13 -0
- package/dist/runtime/rest.js +1 -4
- package/dist/runtime-telemetry.d.ts +15 -0
- package/dist/runtime-telemetry.js +111 -0
- package/dist/schemas/publications.d.ts +10 -10
- package/dist/services.d.ts +2 -9
- package/dist/services.js +3 -10
- package/dist/shell.d.ts +9 -0
- package/dist/shell.js +4 -4
- package/dist/terminal.d.ts +17 -11
- package/dist/terminal.js +27 -44
- package/docs/api-summary.md +28 -23
- package/docs/cdn-usage.md +2 -2
- package/docs/getting-started.md +13 -13
- package/examples/basic.ts +1 -1
- package/examples/git-merge-smoke.ts +1 -4
- package/examples/laravel-load-test.ts +67 -80
- package/examples/notebook-readonly-smoke.ts +30 -33
- package/package.json +1 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export class RuntimeTelemetry {
|
|
2
|
+
constructor(okra) {
|
|
3
|
+
this.okra = okra;
|
|
4
|
+
this.references = new Map();
|
|
5
|
+
this.synchronization = Promise.resolve();
|
|
6
|
+
if (okra.runtimeTransport === 'realtime') {
|
|
7
|
+
okra.onDidConnect(() => {
|
|
8
|
+
if (this.references.size > 0) {
|
|
9
|
+
void this.synchronize();
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async acquire(feature) {
|
|
15
|
+
this.references.set(feature, (this.references.get(feature) ?? 0) + 1);
|
|
16
|
+
try {
|
|
17
|
+
await this.synchronize();
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
this.removeReference(feature);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
let released = false;
|
|
24
|
+
return async () => {
|
|
25
|
+
if (released) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
released = true;
|
|
29
|
+
this.removeReference(feature);
|
|
30
|
+
await this.synchronize();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
removeReference(feature) {
|
|
34
|
+
const references = this.references.get(feature) ?? 0;
|
|
35
|
+
if (references <= 1) {
|
|
36
|
+
this.references.delete(feature);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.references.set(feature, references - 1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
synchronize() {
|
|
43
|
+
this.synchronization = this.synchronization.catch(() => { }).then(async () => {
|
|
44
|
+
const features = Array.from(this.references.keys());
|
|
45
|
+
if (features.length === 0) {
|
|
46
|
+
await this.okra.invoke('container.stop-telemetry');
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
await this.okra.invoke('container.stream-telemetry', { features });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return this.synchronization;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function watchRuntimeTelemetry(okra, telemetry, feature, event, transform, options = {}) {
|
|
56
|
+
let subscription = null;
|
|
57
|
+
let release = null;
|
|
58
|
+
let closed = false;
|
|
59
|
+
let abort = null;
|
|
60
|
+
const stop = async () => {
|
|
61
|
+
if (closed) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
closed = true;
|
|
65
|
+
subscription?.dispose();
|
|
66
|
+
subscription = null;
|
|
67
|
+
if (abort && options.signal) {
|
|
68
|
+
options.signal.removeEventListener('abort', abort);
|
|
69
|
+
}
|
|
70
|
+
abort = null;
|
|
71
|
+
await release?.();
|
|
72
|
+
release = null;
|
|
73
|
+
};
|
|
74
|
+
return new ReadableStream({
|
|
75
|
+
start(controller) {
|
|
76
|
+
subscription = okra.listen(event, (data) => {
|
|
77
|
+
if (!closed) {
|
|
78
|
+
controller.enqueue(transform(data));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
if (options.signal) {
|
|
82
|
+
abort = () => {
|
|
83
|
+
void stop().finally(() => controller.error(options.signal?.reason ?? new Error('Aborted')));
|
|
84
|
+
};
|
|
85
|
+
if (options.signal.aborted) {
|
|
86
|
+
abort();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
options.signal.addEventListener('abort', abort, { once: true });
|
|
90
|
+
}
|
|
91
|
+
void telemetry.acquire(feature).then(async (releaseTelemetry) => {
|
|
92
|
+
if (closed) {
|
|
93
|
+
await releaseTelemetry();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
release = releaseTelemetry;
|
|
97
|
+
}).catch((error) => {
|
|
98
|
+
if (!closed) {
|
|
99
|
+
closed = true;
|
|
100
|
+
subscription?.dispose();
|
|
101
|
+
if (abort && options.signal) {
|
|
102
|
+
options.signal.removeEventListener('abort', abort);
|
|
103
|
+
}
|
|
104
|
+
abort = null;
|
|
105
|
+
controller.error(error);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
cancel: stop,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
@@ -64,12 +64,12 @@ export declare const PublicationProtectionModeSchema: z.ZodEnum<{
|
|
|
64
64
|
password: "password";
|
|
65
65
|
}>;
|
|
66
66
|
export declare const PublicationLogStreamSchema: z.ZodEnum<{
|
|
67
|
-
build: "build";
|
|
68
67
|
runtime: "runtime";
|
|
68
|
+
build: "build";
|
|
69
69
|
}>;
|
|
70
70
|
export declare const PublishStreamLogStreamSchema: z.ZodEnum<{
|
|
71
|
-
build: "build";
|
|
72
71
|
runtime: "runtime";
|
|
72
|
+
build: "build";
|
|
73
73
|
publish: "publish";
|
|
74
74
|
}>;
|
|
75
75
|
export declare const PublicationEventDataSchema: z.ZodObject<{
|
|
@@ -82,8 +82,8 @@ export declare const PublicationEventDataSchema: z.ZodObject<{
|
|
|
82
82
|
export declare const PublicationLogChunkDataSchema: z.ZodObject<{
|
|
83
83
|
sequence: z.ZodNumber;
|
|
84
84
|
stream: z.ZodEnum<{
|
|
85
|
-
build: "build";
|
|
86
85
|
runtime: "runtime";
|
|
86
|
+
build: "build";
|
|
87
87
|
}>;
|
|
88
88
|
content: z.ZodString;
|
|
89
89
|
createdAt: z.ZodNullable<z.ZodString>;
|
|
@@ -99,8 +99,8 @@ export declare const PublishStreamPhaseSchema: z.ZodObject<{
|
|
|
99
99
|
}, z.core.$strict>;
|
|
100
100
|
export declare const PublishStreamLogSchema: z.ZodObject<{
|
|
101
101
|
stream: z.ZodEnum<{
|
|
102
|
-
build: "build";
|
|
103
102
|
runtime: "runtime";
|
|
103
|
+
build: "build";
|
|
104
104
|
publish: "publish";
|
|
105
105
|
}>;
|
|
106
106
|
content: z.ZodString;
|
|
@@ -135,8 +135,8 @@ export declare const PublishStreamPhaseEventSchema: z.ZodObject<{
|
|
|
135
135
|
}, z.core.$strict>;
|
|
136
136
|
export declare const PublishStreamLogEventSchema: z.ZodObject<{
|
|
137
137
|
stream: z.ZodEnum<{
|
|
138
|
-
build: "build";
|
|
139
138
|
runtime: "runtime";
|
|
139
|
+
build: "build";
|
|
140
140
|
publish: "publish";
|
|
141
141
|
}>;
|
|
142
142
|
content: z.ZodString;
|
|
@@ -172,8 +172,8 @@ export declare const PublishStreamEventSchema: z.ZodDiscriminatedUnion<[z.ZodObj
|
|
|
172
172
|
type: z.ZodLiteral<"phase">;
|
|
173
173
|
}, z.core.$strict>, z.ZodObject<{
|
|
174
174
|
stream: z.ZodEnum<{
|
|
175
|
-
build: "build";
|
|
176
175
|
runtime: "runtime";
|
|
176
|
+
build: "build";
|
|
177
177
|
publish: "publish";
|
|
178
178
|
}>;
|
|
179
179
|
content: z.ZodString;
|
|
@@ -223,8 +223,8 @@ export declare const PublishStreamSseLogEventSchema: z.ZodObject<{
|
|
|
223
223
|
event: z.ZodLiteral<"log">;
|
|
224
224
|
data: z.ZodObject<{
|
|
225
225
|
stream: z.ZodEnum<{
|
|
226
|
-
build: "build";
|
|
227
226
|
runtime: "runtime";
|
|
227
|
+
build: "build";
|
|
228
228
|
publish: "publish";
|
|
229
229
|
}>;
|
|
230
230
|
content: z.ZodString;
|
|
@@ -293,8 +293,8 @@ export declare const PublishStreamSseEventSchema: z.ZodPipe<z.ZodDiscriminatedUn
|
|
|
293
293
|
event: z.ZodLiteral<"log">;
|
|
294
294
|
data: z.ZodObject<{
|
|
295
295
|
stream: z.ZodEnum<{
|
|
296
|
-
build: "build";
|
|
297
296
|
runtime: "runtime";
|
|
297
|
+
build: "build";
|
|
298
298
|
publish: "publish";
|
|
299
299
|
}>;
|
|
300
300
|
content: z.ZodString;
|
|
@@ -350,7 +350,7 @@ export declare const PublishStreamSseEventSchema: z.ZodPipe<z.ZodDiscriminatedUn
|
|
|
350
350
|
status?: "running" | "failed" | "completed";
|
|
351
351
|
data?: Record<string, unknown>;
|
|
352
352
|
} | {
|
|
353
|
-
stream: "
|
|
353
|
+
stream: "runtime" | "build" | "publish";
|
|
354
354
|
content: string;
|
|
355
355
|
type: "log";
|
|
356
356
|
} | {
|
|
@@ -370,7 +370,7 @@ export declare const PublishStreamSseEventSchema: z.ZodPipe<z.ZodDiscriminatedUn
|
|
|
370
370
|
} | {
|
|
371
371
|
event: "log";
|
|
372
372
|
data: {
|
|
373
|
-
stream: "
|
|
373
|
+
stream: "runtime" | "build" | "publish";
|
|
374
374
|
content: string;
|
|
375
375
|
};
|
|
376
376
|
} | {
|
package/dist/services.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Action,
|
|
1
|
+
import { Action, NotebookInstance } from './index.js';
|
|
2
2
|
export type NotebookServiceKind = 'app' | 'web' | 'cache' | 'task';
|
|
3
3
|
export type NotebookServiceSource = 'built_in' | 'setup_task';
|
|
4
4
|
export type NotebookServiceState = 'running' | 'starting' | 'stopping' | 'backoff' | 'exited' | 'fatal' | 'stopped' | 'unknown';
|
|
@@ -64,20 +64,13 @@ export interface ServiceLogOptions {
|
|
|
64
64
|
tail?: number;
|
|
65
65
|
follow?: false;
|
|
66
66
|
}
|
|
67
|
-
export interface ServiceLogStream {
|
|
68
|
-
id: string;
|
|
69
|
-
output: ReadableStream<string>;
|
|
70
|
-
stop(): Promise<boolean>;
|
|
71
|
-
}
|
|
72
67
|
export default class Services {
|
|
73
68
|
protected okra: NotebookInstance;
|
|
74
69
|
constructor(okra: NotebookInstance);
|
|
75
70
|
list(): Promise<NotebookServiceStatus[]>;
|
|
76
71
|
run(name: NotebookServiceName, command?: NotebookServiceCommand): Promise<NotebookServiceStatus>;
|
|
77
72
|
stop(name: NotebookServiceName): Promise<NotebookServiceStatus>;
|
|
78
|
-
|
|
79
|
-
listen<T extends keyof ServiceEvents>(event: T, handler: (data: ServiceEvents[T]) => void): Disposable;
|
|
80
|
-
logs(name: NotebookServiceName, options: ServiceLogStreamOptions): ServiceLogStream;
|
|
73
|
+
logs(name: NotebookServiceName, options: ServiceLogStreamOptions): ReadableStream<string>;
|
|
81
74
|
logs(name: NotebookServiceName, options?: ServiceLogOptions): Promise<string>;
|
|
82
75
|
private followLogs;
|
|
83
76
|
}
|
package/dist/services.js
CHANGED
|
@@ -18,12 +18,6 @@ export default class Services {
|
|
|
18
18
|
stop(name) {
|
|
19
19
|
return this.okra.invoke('service.stop', { name });
|
|
20
20
|
}
|
|
21
|
-
onLog(id, handler) {
|
|
22
|
-
return this.okra.listen(`service.log.${id}`, handler);
|
|
23
|
-
}
|
|
24
|
-
listen(event, handler) {
|
|
25
|
-
return this.okra.listen(event, handler);
|
|
26
|
-
}
|
|
27
21
|
logs(name, options = {}) {
|
|
28
22
|
if (options.follow) {
|
|
29
23
|
return this.followLogs(name, options);
|
|
@@ -80,10 +74,10 @@ export default class Services {
|
|
|
80
74
|
close();
|
|
81
75
|
return this.okra.invoke('service.stop-logs', { id });
|
|
82
76
|
});
|
|
83
|
-
|
|
77
|
+
return new ReadableStream({
|
|
84
78
|
start: (_controller) => {
|
|
85
79
|
controller = _controller;
|
|
86
|
-
disposables.add(this.
|
|
80
|
+
disposables.add(this.okra.listen(`service.log.${id}`, (data) => {
|
|
87
81
|
controller?.enqueue(data.output);
|
|
88
82
|
}));
|
|
89
83
|
void this.okra
|
|
@@ -98,9 +92,8 @@ export default class Services {
|
|
|
98
92
|
});
|
|
99
93
|
},
|
|
100
94
|
cancel: () => {
|
|
101
|
-
|
|
95
|
+
return stop().then(() => undefined);
|
|
102
96
|
},
|
|
103
97
|
});
|
|
104
|
-
return { id, output, stop };
|
|
105
98
|
}
|
|
106
99
|
}
|
package/dist/shell.d.ts
CHANGED
|
@@ -49,6 +49,15 @@ export declare class ProcessResult implements ProcessResultData {
|
|
|
49
49
|
constructor(output: string, stdout: string, stderr: string, exitCode: number);
|
|
50
50
|
throw(): this;
|
|
51
51
|
}
|
|
52
|
+
export declare class ProcessReadable<T> {
|
|
53
|
+
readonly stream: ReadableStream<T>;
|
|
54
|
+
private controller;
|
|
55
|
+
private closed;
|
|
56
|
+
constructor();
|
|
57
|
+
enqueue(value: T): void;
|
|
58
|
+
close(): void;
|
|
59
|
+
fail(error: unknown): void;
|
|
60
|
+
}
|
|
52
61
|
export declare class ShellProcess {
|
|
53
62
|
readonly id: string;
|
|
54
63
|
private readonly okra;
|
package/dist/shell.js
CHANGED
|
@@ -27,7 +27,7 @@ export class ProcessResult {
|
|
|
27
27
|
return this;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
class
|
|
30
|
+
export class ProcessReadable {
|
|
31
31
|
constructor() {
|
|
32
32
|
this.controller = null;
|
|
33
33
|
this.closed = false;
|
|
@@ -67,9 +67,9 @@ export class ShellProcess {
|
|
|
67
67
|
constructor(id, okra, command, opts) {
|
|
68
68
|
this.id = id;
|
|
69
69
|
this.okra = okra;
|
|
70
|
-
const output = new
|
|
71
|
-
const stdout = new
|
|
72
|
-
const stderr = new
|
|
70
|
+
const output = new ProcessReadable();
|
|
71
|
+
const stdout = new ProcessReadable();
|
|
72
|
+
const stderr = new ProcessReadable();
|
|
73
73
|
this.output = output.stream;
|
|
74
74
|
this.stdout = stdout.stream;
|
|
75
75
|
this.stderr = stderr.stream;
|
package/dist/terminal.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Action,
|
|
1
|
+
import { Action, NotebookInstance } from './index.js';
|
|
2
2
|
export interface Task {
|
|
3
3
|
id: string;
|
|
4
4
|
command: string | string[];
|
|
@@ -14,7 +14,7 @@ export interface TerminalCreateInput {
|
|
|
14
14
|
kind: string;
|
|
15
15
|
size: [number, number];
|
|
16
16
|
command?: string | string[];
|
|
17
|
-
env?: Record<string, string>;
|
|
17
|
+
env?: Record<string, string | number | boolean>;
|
|
18
18
|
cwd?: string;
|
|
19
19
|
}
|
|
20
20
|
export interface TerminalSpawnInput {
|
|
@@ -66,7 +66,7 @@ export interface TerminalActions {
|
|
|
66
66
|
}
|
|
67
67
|
export interface SandboxProcess {
|
|
68
68
|
wait(): Promise<number>;
|
|
69
|
-
input: WritableStream<string>;
|
|
69
|
+
input: WritableStream<string | Uint8Array>;
|
|
70
70
|
output: ReadableStream<string>;
|
|
71
71
|
kill(): Promise<boolean>;
|
|
72
72
|
resize(dimensions: {
|
|
@@ -87,21 +87,27 @@ export interface SpawnOptions {
|
|
|
87
87
|
tty?: boolean;
|
|
88
88
|
abortSignal?: AbortSignal;
|
|
89
89
|
}
|
|
90
|
-
export
|
|
90
|
+
export interface TerminalOptions {
|
|
91
|
+
command?: string | string[];
|
|
92
|
+
args?: string[];
|
|
93
|
+
kind?: string;
|
|
94
|
+
size?: [number, number];
|
|
95
|
+
cwd?: string;
|
|
96
|
+
env?: Record<string, string | number | boolean>;
|
|
97
|
+
id?: string;
|
|
98
|
+
osc?: boolean;
|
|
99
|
+
tty?: boolean;
|
|
100
|
+
abortSignal?: AbortSignal;
|
|
101
|
+
}
|
|
102
|
+
export default class Terminals {
|
|
91
103
|
protected okra: NotebookInstance;
|
|
92
104
|
constructor(okra: NotebookInstance);
|
|
93
105
|
list(): Promise<Task[]>;
|
|
94
|
-
create(
|
|
95
|
-
onStarted(handler: (t: Task) => void): Disposable;
|
|
96
|
-
resize(id: string, size: [number, number]): Promise<boolean>;
|
|
97
|
-
onOutput(id: string, handler: (data: TerminalEvents['terminal.output']) => void): Disposable;
|
|
98
|
-
input(id: string, input: string): Promise<boolean>;
|
|
99
|
-
listen<T extends keyof TerminalEvents>(event: T, handler: (data: TerminalEvents[T]) => void): Disposable;
|
|
106
|
+
create(options?: TerminalOptions): Promise<SandboxProcess & Task>;
|
|
100
107
|
attach(id: string, opts?: {
|
|
101
108
|
replayHistory?: boolean;
|
|
102
109
|
abortSignal?: AbortSignal;
|
|
103
110
|
}): Promise<(SandboxProcess & Task) | false>;
|
|
104
|
-
spawn(command: string, args: string[], opts?: SpawnOptions): Promise<SandboxProcess & Task>;
|
|
105
111
|
private processHandle;
|
|
106
112
|
}
|
|
107
113
|
export {};
|
package/dist/terminal.js
CHANGED
|
@@ -2,30 +2,34 @@ import { nanoid } from 'nanoid';
|
|
|
2
2
|
import { once } from './utils/promise.js';
|
|
3
3
|
const TERMINAL_INPUT_FLUSH_DELAY_MS = 8;
|
|
4
4
|
const terminalInputFlushPattern = /[\x00-\x1f\x7f]/;
|
|
5
|
-
export default class
|
|
5
|
+
export default class Terminals {
|
|
6
6
|
constructor(okra) {
|
|
7
7
|
this.okra = okra;
|
|
8
8
|
}
|
|
9
9
|
list() {
|
|
10
10
|
return this.okra.invoke('terminal.list');
|
|
11
11
|
}
|
|
12
|
-
create(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
12
|
+
async create(options = {}) {
|
|
13
|
+
const id = options.id ?? nanoid();
|
|
14
|
+
const handle = this.processHandle(id, options.abortSignal);
|
|
15
|
+
const command = typeof options.command === 'string' && options.args?.length
|
|
16
|
+
? [options.command, ...options.args]
|
|
17
|
+
: options.command;
|
|
18
|
+
const { abortSignal, args: _args, ...input } = options;
|
|
19
|
+
try {
|
|
20
|
+
const task = await this.okra.invoke('terminal.create', {
|
|
21
|
+
...input,
|
|
22
|
+
id,
|
|
23
|
+
kind: options.kind ?? 'bash',
|
|
24
|
+
size: options.size ?? [80, 24],
|
|
25
|
+
command,
|
|
26
|
+
}, { abortSignal });
|
|
27
|
+
return { ...handle.process, ...task };
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
handle.dispose();
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
29
33
|
}
|
|
30
34
|
async attach(id, opts) {
|
|
31
35
|
const handle = this.processHandle(id, opts?.abortSignal);
|
|
@@ -48,28 +52,6 @@ export default class Terminal {
|
|
|
48
52
|
throw error;
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
|
-
async spawn(command, args, opts) {
|
|
52
|
-
const id = opts?.id || nanoid();
|
|
53
|
-
const handle = this.processHandle(id, opts?.abortSignal);
|
|
54
|
-
const { abortSignal, ...otherOpts } = opts ?? {};
|
|
55
|
-
try {
|
|
56
|
-
const result = await this.okra.invoke('terminal.spawn', {
|
|
57
|
-
command: [command, ...args],
|
|
58
|
-
opts: {
|
|
59
|
-
id,
|
|
60
|
-
...otherOpts,
|
|
61
|
-
},
|
|
62
|
-
}, { abortSignal });
|
|
63
|
-
return {
|
|
64
|
-
...handle.process,
|
|
65
|
-
...result,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
handle.dispose();
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
55
|
processHandle(id, abortSignal) {
|
|
74
56
|
const disposables = new Set();
|
|
75
57
|
let abortHandler;
|
|
@@ -95,7 +77,7 @@ export default class Terminal {
|
|
|
95
77
|
}
|
|
96
78
|
const input = pendingInput;
|
|
97
79
|
pendingInput = '';
|
|
98
|
-
void this.input
|
|
80
|
+
void this.okra.send('terminal.input', { id, input });
|
|
99
81
|
};
|
|
100
82
|
const scheduleInputFlush = () => {
|
|
101
83
|
if (inputFlushTimer) {
|
|
@@ -103,7 +85,8 @@ export default class Terminal {
|
|
|
103
85
|
}
|
|
104
86
|
inputFlushTimer = setTimeout(flushInput, TERMINAL_INPUT_FLUSH_DELAY_MS);
|
|
105
87
|
};
|
|
106
|
-
const queueInput = (
|
|
88
|
+
const queueInput = (value) => {
|
|
89
|
+
const chunk = typeof value === 'string' ? value : new TextDecoder().decode(value);
|
|
107
90
|
pendingInput += chunk;
|
|
108
91
|
if (terminalInputFlushPattern.test(chunk)) {
|
|
109
92
|
flushInput();
|
|
@@ -124,7 +107,7 @@ export default class Terminal {
|
|
|
124
107
|
const output = new ReadableStream({
|
|
125
108
|
start: (_controller) => {
|
|
126
109
|
controller = _controller;
|
|
127
|
-
disposables.add(this.listen(`terminal.output.${id}`, (data) => {
|
|
110
|
+
disposables.add(this.okra.listen(`terminal.output.${id}`, (data) => {
|
|
128
111
|
controller?.enqueue(data.output);
|
|
129
112
|
}));
|
|
130
113
|
},
|
|
@@ -134,7 +117,7 @@ export default class Terminal {
|
|
|
134
117
|
},
|
|
135
118
|
});
|
|
136
119
|
const completion = new Promise((resolve) => {
|
|
137
|
-
disposables.add(this.listen(`terminal.close.${id}`, (data) => {
|
|
120
|
+
disposables.add(this.okra.listen(`terminal.close.${id}`, (data) => {
|
|
138
121
|
if (controller) {
|
|
139
122
|
try {
|
|
140
123
|
controller.close();
|
package/docs/api-summary.md
CHANGED
|
@@ -32,36 +32,46 @@ Connection lifecycle methods, streaming actions, and event subscriptions require
|
|
|
32
32
|
|
|
33
33
|
- Lifecycle: `ready()`, `connected()`, `whenConnected()`, `reconnect()`, `dispose()`
|
|
34
34
|
- Notebook actions: `fork(input?)`, `destroy()`, `stop()`, `restart()`, `ping()`, `update()`
|
|
35
|
-
- Processes: `run(command, args?, options?)` returning native `stdin`, `stdout`, `stderr`, ordered `output`, `
|
|
35
|
+
- Processes: `exec(command, args?, options?)`, or `run(command, args?, options?)` returning native `stdin`, `stdout`, `stderr`, ordered `output`, `wait()`, and `kill()`
|
|
36
36
|
- Events: `listen(event, handler)`, `onDidConnect(handler)`, `onDidDisconnect(handler)`, `onDidInitialize(handler)`
|
|
37
37
|
- Raw call: `invoke(action, data?, options?)`
|
|
38
38
|
|
|
39
39
|
## Services
|
|
40
40
|
|
|
41
|
-
### Filesystem (`notebook.
|
|
41
|
+
### Filesystem (`notebook.files`)
|
|
42
42
|
|
|
43
|
-
- File data: `
|
|
44
|
-
- File management: `move()`, `
|
|
45
|
-
- Directory: `
|
|
43
|
+
- File data: `read()`, `readText()`, `readStream()`, `write()`, `tail()`, `stat()`, `exists()`
|
|
44
|
+
- File management: `move()`, `copy()`, `remove()`
|
|
45
|
+
- Directory: `createDirectory()`, `list()`, `tree()`
|
|
46
46
|
- Search: `find()`, `search()`
|
|
47
|
-
- Streaming/monitoring: `watch()`, `download()`
|
|
47
|
+
- Streaming/monitoring: `readStream()`, `watch()`, `download()`
|
|
48
|
+
- `tail()` is an eager last-lines snapshot; it does not follow future appends.
|
|
48
49
|
|
|
49
|
-
### Terminal (`notebook.
|
|
50
|
+
### Terminal (`notebook.terminals`)
|
|
50
51
|
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
52
|
+
- `list()` returns terminal metadata
|
|
53
|
+
- `create(options?)` returns a terminal handle
|
|
54
|
+
- `attach(id, options?)` returns a terminal handle
|
|
55
|
+
- Handles expose `input`, `output`, `wait()`, `resize()`, and `kill()`
|
|
54
56
|
|
|
55
57
|
### Container (`notebook.container`)
|
|
56
58
|
|
|
57
59
|
- Lifecycle: `start()`, `stop()`, `state()`
|
|
58
|
-
- Ports: `openedPorts()`, `onPort(handler)`
|
|
59
60
|
- Runtime config: `setPhp(version)`
|
|
60
|
-
- Telemetry: `enableTelemetry(features)`, `stopTelemetry()`, `listen(event, handler)`
|
|
61
61
|
|
|
62
|
-
###
|
|
62
|
+
### Runtime observability
|
|
63
63
|
|
|
64
|
-
- `
|
|
64
|
+
- `notebook.logs.follow({ signal? })` returns `ReadableStream<RuntimeLogEntry>`
|
|
65
|
+
- `notebook.ports.list()` returns the current preview ports
|
|
66
|
+
- `notebook.ports.watch({ signal? })` returns `ReadableStream<PortInfo[]>`
|
|
67
|
+
- `notebook.metrics.current()` returns the current CPU, memory, and disk sample
|
|
68
|
+
- `notebook.metrics.watch({ signal? })` returns `ReadableStream<ContainerStats>`
|
|
69
|
+
|
|
70
|
+
### Processes
|
|
71
|
+
|
|
72
|
+
- `notebook.run(command, args?, options?)` returns a streaming process handle
|
|
73
|
+
- `notebook.exec(command, args?, options?)` returns a buffered `ProcessResult` for one-shot commands
|
|
74
|
+
- Process handles expose `output`, `stdout`, `stderr`, `stdin`, `wait()`, and `kill()`
|
|
65
75
|
|
|
66
76
|
### Services (`notebook.services`)
|
|
67
77
|
|
|
@@ -70,13 +80,13 @@ Connection lifecycle methods, streaming actions, and event subscriptions require
|
|
|
70
80
|
- `run(name, command?)`
|
|
71
81
|
- `stop(name)`
|
|
72
82
|
- `logs(name, { tail? })`
|
|
73
|
-
- `logs(name, { follow: true, tail?, id? })` returning `
|
|
74
|
-
- Events: `listen()`, `onLog(id, handler)`
|
|
83
|
+
- `logs(name, { follow: true, tail?, id? })` returning `ReadableStream<string>`; cancel the stream to stop following
|
|
75
84
|
|
|
76
85
|
### Composer (`notebook.composer`)
|
|
77
86
|
|
|
78
|
-
- Core: `
|
|
79
|
-
- Helpers: `install()`, `update()`, `require()`, `remove()`, `dumpAutoload()`, `packages()
|
|
87
|
+
- Core: `run(command, args?, options?)`
|
|
88
|
+
- Helpers: `install()`, `update()`, `require()`, `remove()`, `dumpAutoload()`, `packages()`
|
|
89
|
+
- Command handles expose `output`, `stdout`, `stderr`, `wait()`, and `kill()`
|
|
80
90
|
|
|
81
91
|
### Git (`notebook.git`)
|
|
82
92
|
|
|
@@ -126,11 +136,6 @@ Connection lifecycle methods, streaming actions, and event subscriptions require
|
|
|
126
136
|
- A publish run exposes `events()` as an `AsyncIterable`, `result()`, and `publication()`.
|
|
127
137
|
- Built-in provider names are `cloudflare-containers`, `ssh-server`, and `laravel-cloud`. Provider maps support TypeScript declaration merging.
|
|
128
138
|
|
|
129
|
-
### Log (`notebook.log`)
|
|
130
|
-
|
|
131
|
-
- `stream(handler)`
|
|
132
|
-
- `listen(event, handler)`
|
|
133
|
-
|
|
134
139
|
## Common Errors
|
|
135
140
|
|
|
136
141
|
- `ApiError` for HTTP API failures
|
package/docs/cdn-usage.md
CHANGED
|
@@ -18,7 +18,7 @@ Do not hardcode long-lived private API tokens in public frontend code. Use short
|
|
|
18
18
|
const notebook = await client.notebook.get('your-notebook-id');
|
|
19
19
|
await notebook.ready();
|
|
20
20
|
|
|
21
|
-
const result = await notebook.
|
|
21
|
+
const result = await notebook.exec('php -v', { tty: false });
|
|
22
22
|
result.throw();
|
|
23
23
|
console.log(result.output);
|
|
24
24
|
</script>
|
|
@@ -45,7 +45,7 @@ Do not hardcode long-lived private API tokens in public frontend code. Use short
|
|
|
45
45
|
|
|
46
46
|
client.notebook.get('your-notebook-id').then(async (notebook) => {
|
|
47
47
|
await notebook.ready();
|
|
48
|
-
const result = await notebook.
|
|
48
|
+
const result = await notebook.exec('php -v', { tty: false });
|
|
49
49
|
console.log(result.output);
|
|
50
50
|
notebook.dispose();
|
|
51
51
|
});
|