@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.
@@ -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: "build" | "runtime" | "publish";
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: "build" | "runtime" | "publish";
373
+ stream: "runtime" | "build" | "publish";
374
374
  content: string;
375
375
  };
376
376
  } | {
@@ -1,4 +1,4 @@
1
- import { Action, Disposable, NotebookInstance } from './index.js';
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
- onLog(id: string, handler: (data: ServiceEvents['service.log']) => void): Disposable;
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
- const output = new ReadableStream({
77
+ return new ReadableStream({
84
78
  start: (_controller) => {
85
79
  controller = _controller;
86
- disposables.add(this.onLog(id, (data) => {
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
- void stop();
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 OutputStream {
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 OutputStream();
71
- const stdout = new OutputStream();
72
- const stderr = new OutputStream();
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;
@@ -1,4 +1,4 @@
1
- import { Action, Disposable, NotebookInstance } from './index.js';
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 default class Terminal {
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(input: TerminalCreateInput): Promise<Task>;
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 Terminal {
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(input) {
13
- return this.okra.invoke('terminal.create', input);
14
- }
15
- onStarted(handler) {
16
- return this.okra.listen('terminal.started', handler);
17
- }
18
- resize(id, size) {
19
- return this.okra.invoke('terminal.resize', { id, width: size[0], height: size[1] });
20
- }
21
- onOutput(id, handler) {
22
- return this.okra.listen(`terminal.output.${id}`, handler);
23
- }
24
- input(id, input) {
25
- return Promise.resolve(this.okra.send('terminal.input', { id, input }));
26
- }
27
- listen(event, handler) {
28
- return this.okra.listen(event, handler);
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(id, 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 = (chunk) => {
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();
@@ -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`, `exit`, and `kill()`
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.file`)
41
+ ### Filesystem (`notebook.files`)
42
42
 
43
- - File data: `info()`, `readFile()`, `write()`, `writeFile()`, `tail()`, `stat()`, `exists()`
44
- - File management: `move()`, `rename()`, `copy()`, `remove()`, `delete()`
45
- - Directory: `mkdir()`, `createDirectory()`, `readDirectory()`, `tree()`
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.terminal`)
50
+ ### Terminal (`notebook.terminals`)
50
51
 
51
- - Terminal control: `list()`, `create()`, `attach()`, `resize()`, `input()`
52
- - Process API: `spawn(command, args, opts?)`, `attach(id, opts?)`
53
- - Events: `listen()`, `onStarted()`, `onOutput(id, handler)`
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
- ### Shell (`notebook.shell`)
62
+ ### Runtime observability
63
63
 
64
- - `run(command, args?, options?)` returning the same process handle as `notebook.run()`
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 `{ id, output, stop() }`
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: `invoke(command, args?, options?)`
79
- - Helpers: `install()`, `update()`, `require()`, `remove()`, `dumpAutoload()`, `packages()`, `stream(handler)`
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.run('php -v', { tty: false }).exit;
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.run('php -v', { tty: false }).exit;
48
+ const result = await notebook.exec('php -v', { tty: false });
49
49
  console.log(result.output);
50
50
  notebook.dispose();
51
51
  });