@phpsandbox/sdk 0.0.16 → 0.0.17
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 +134 -643
- package/dist/browser/phpsandbox-sdk.esm.js.map +2 -2
- package/dist/browser/phpsandbox-sdk.esm.min.js.map +2 -2
- package/dist/browser/phpsandbox-sdk.iife.js.map +2 -2
- package/dist/browser/phpsandbox-sdk.iife.min.js.map +2 -2
- package/dist/shell.d.ts +2 -2
- package/dist/shell.d.ts.map +1 -1
- package/dist/shell.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,46 +1,6 @@
|
|
|
1
1
|
# PHPSandbox SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [PHPSandbox SDK](#phpsandbox-sdk)
|
|
8
|
-
- [Table of Contents](#table-of-contents)
|
|
9
|
-
- [Installation](#installation)
|
|
10
|
-
- [Quick Start](#quick-start)
|
|
11
|
-
- [Authentication](#authentication)
|
|
12
|
-
- [Core Concepts](#core-concepts)
|
|
13
|
-
- [Client](#client)
|
|
14
|
-
- [NotebookInstance](#notebookinstance)
|
|
15
|
-
- [Event-Driven Architecture](#event-driven-architecture)
|
|
16
|
-
- [API Reference](#api-reference)
|
|
17
|
-
- [Client](#client-1)
|
|
18
|
-
- [NotebookApi Methods](#notebookapi-methods)
|
|
19
|
-
- [NotebookInstance](#notebookinstance-1)
|
|
20
|
-
- [Filesystem](#filesystem)
|
|
21
|
-
- [File Search Example](#file-search-example)
|
|
22
|
-
- [Terminal](#terminal)
|
|
23
|
-
- [Terminal Usage Example](#terminal-usage-example)
|
|
24
|
-
- [Container](#container)
|
|
25
|
-
- [Language Server Protocol (LSP)](#language-server-protocol-lsp)
|
|
26
|
-
- [Composer](#composer)
|
|
27
|
-
- [Git](#git)
|
|
28
|
-
- [Laravel](#laravel)
|
|
29
|
-
- [REPL](#repl)
|
|
30
|
-
- [Shell](#shell)
|
|
31
|
-
- [Auth](#auth)
|
|
32
|
-
- [Logging](#logging)
|
|
33
|
-
- [Event System](#event-system)
|
|
34
|
-
- [Error Handling](#error-handling)
|
|
35
|
-
- [Common Error Types](#common-error-types)
|
|
36
|
-
- [Examples](#examples)
|
|
37
|
-
- [Complete Laravel Application Setup](#complete-laravel-application-setup)
|
|
38
|
-
- [File Processing Pipeline](#file-processing-pipeline)
|
|
39
|
-
- [Real-time Development Environment](#real-time-development-environment)
|
|
40
|
-
- [TypeScript Support](#typescript-support)
|
|
41
|
-
- [Generic Types](#generic-types)
|
|
42
|
-
- [Support and Contributing](#support-and-contributing)
|
|
43
|
-
- [License](#license)
|
|
3
|
+
TypeScript SDK for working with PHPSandbox notebooks: create environments, edit files, run commands, and stream real-time events.
|
|
44
4
|
|
|
45
5
|
## Installation
|
|
46
6
|
|
|
@@ -48,691 +8,222 @@ A comprehensive TypeScript SDK for interacting with cloud-based PHP development
|
|
|
48
8
|
npm install @phpsandbox/sdk
|
|
49
9
|
```
|
|
50
10
|
|
|
11
|
+
Node.js `>=18` is required.
|
|
12
|
+
|
|
51
13
|
## Quick Start
|
|
52
14
|
|
|
53
|
-
```
|
|
15
|
+
```ts
|
|
54
16
|
import { PHPSandbox } from '@phpsandbox/sdk';
|
|
55
17
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// Create and initialize a new notebook
|
|
60
|
-
const notebook = await client.notebook.create('laravel');
|
|
18
|
+
const token = process.env.PHPSANDBOX_TOKEN;
|
|
19
|
+
if (!token) throw new Error('Missing PHPSANDBOX_TOKEN');
|
|
61
20
|
|
|
62
|
-
|
|
63
|
-
const files = notebook.file;
|
|
64
|
-
const terminal = notebook.terminal;
|
|
65
|
-
const container = notebook.container;
|
|
21
|
+
const client = new PHPSandbox(token);
|
|
66
22
|
|
|
67
|
-
//
|
|
68
|
-
await
|
|
23
|
+
// create() initializes the notebook by default
|
|
24
|
+
const notebook = await client.notebook.create('php');
|
|
69
25
|
|
|
70
|
-
|
|
71
|
-
const process = await terminal.spawn('php', ['index.php']);
|
|
72
|
-
process.output
|
|
73
|
-
.getReader()
|
|
74
|
-
.read()
|
|
75
|
-
.then(({ value }) => {
|
|
76
|
-
console.log(value); // "Hello World!"
|
|
77
|
-
});
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Authentication
|
|
26
|
+
await notebook.file.write('index.php', '<?php echo "Hello from PHPSandbox";');
|
|
81
27
|
|
|
82
|
-
|
|
28
|
+
const process = await notebook.terminal.spawn('php', ['index.php']);
|
|
83
29
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
30
|
+
const reader = process.output.getReader();
|
|
31
|
+
let output = '';
|
|
32
|
+
try {
|
|
33
|
+
while (true) {
|
|
34
|
+
const { done, value } = await reader.read();
|
|
35
|
+
if (done) break;
|
|
36
|
+
output += value;
|
|
37
|
+
}
|
|
38
|
+
} finally {
|
|
39
|
+
reader.releaseLock();
|
|
40
|
+
}
|
|
87
41
|
|
|
88
|
-
|
|
89
|
-
|
|
42
|
+
await process.exit;
|
|
43
|
+
console.log(output.trim());
|
|
90
44
|
|
|
91
|
-
//
|
|
92
|
-
|
|
45
|
+
// close websocket resources when done
|
|
46
|
+
notebook.dispose();
|
|
93
47
|
```
|
|
94
48
|
|
|
95
|
-
##
|
|
96
|
-
|
|
97
|
-
### Client
|
|
49
|
+
## Authentication
|
|
98
50
|
|
|
99
|
-
|
|
51
|
+
Use an API token:
|
|
100
52
|
|
|
101
|
-
|
|
53
|
+
```ts
|
|
54
|
+
import { PHPSandbox } from '@phpsandbox/sdk';
|
|
102
55
|
|
|
103
|
-
|
|
56
|
+
const client = new PHPSandbox(process.env.PHPSANDBOX_TOKEN!);
|
|
57
|
+
```
|
|
104
58
|
|
|
105
|
-
|
|
106
|
-
- **Terminal**: Interactive terminal and process execution
|
|
107
|
-
- **Container**: Environment management and monitoring
|
|
108
|
-
- **LSP**: Language server integration for IDE features
|
|
109
|
-
- **Development Tools**: Composer, Git, Laravel tooling, REPL
|
|
59
|
+
Optional constructor args:
|
|
110
60
|
|
|
111
|
-
|
|
61
|
+
```ts
|
|
62
|
+
new PHPSandbox('token', 'https://api.phpsandbox.io/v1', {
|
|
63
|
+
debug: false,
|
|
64
|
+
startClosed: true,
|
|
65
|
+
});
|
|
66
|
+
```
|
|
112
67
|
|
|
113
|
-
|
|
68
|
+
## Notebook Lifecycle
|
|
114
69
|
|
|
115
|
-
|
|
70
|
+
```ts
|
|
71
|
+
const client = new PHPSandbox(process.env.PHPSANDBOX_TOKEN!);
|
|
116
72
|
|
|
117
|
-
|
|
73
|
+
const created = await client.notebook.create('laravel');
|
|
74
|
+
const opened = await client.notebook.open('notebook-id');
|
|
75
|
+
await opened.ready();
|
|
118
76
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
constructor(token: string, url?: string, options?: PHPSandboxClientOptions);
|
|
77
|
+
const fetched = await client.notebook.get('notebook-id');
|
|
78
|
+
await fetched.ready();
|
|
122
79
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
80
|
+
const forked = await created.fork();
|
|
81
|
+
await forked.delete();
|
|
126
82
|
```
|
|
127
83
|
|
|
128
|
-
|
|
84
|
+
Notes:
|
|
129
85
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
create(template: string, input?: Partial<CreateNotebookInput>, init?: boolean): Promise<NotebookInstance>
|
|
86
|
+
- `create()` and `fork()` initialize automatically.
|
|
87
|
+
- `open()` and `get()` return a notebook instance; call `await notebook.ready()` before using tools.
|
|
133
88
|
|
|
134
|
-
|
|
135
|
-
get(id: string): Promise<NotebookInstance>
|
|
89
|
+
## Services At A Glance
|
|
136
90
|
|
|
137
|
-
|
|
138
|
-
fork(id: string): Promise<NotebookInstance>
|
|
91
|
+
Each `NotebookInstance` exposes service clients:
|
|
139
92
|
|
|
140
|
-
|
|
141
|
-
|
|
93
|
+
- `notebook.file` (`Filesystem`)
|
|
94
|
+
- `notebook.terminal` (`Terminal`)
|
|
95
|
+
- `notebook.container` (`Container`)
|
|
96
|
+
- `notebook.shell` (`Shell`)
|
|
97
|
+
- `notebook.composer` (`Composer`)
|
|
98
|
+
- `notebook.git` (`Git`)
|
|
99
|
+
- `notebook.lsp` (`Lsp`)
|
|
100
|
+
- `notebook.repl` (`Repl`)
|
|
101
|
+
- `notebook.laravel` (`Laravel`)
|
|
102
|
+
- `notebook.auth` (`Auth`)
|
|
103
|
+
- `notebook.log` (`Log`)
|
|
142
104
|
|
|
143
|
-
|
|
144
|
-
openFromData(data: NotebookData): Promise<NotebookInstance>
|
|
145
|
-
```
|
|
105
|
+
## Common Operations
|
|
146
106
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
const notebook = await client.notebook.create(
|
|
151
|
-
'php',
|
|
152
|
-
{
|
|
153
|
-
title: 'Imported Repo',
|
|
154
|
-
import: {
|
|
155
|
-
provider: 'github',
|
|
156
|
-
repo: 'https://github.com/acme/private-repo.git',
|
|
157
|
-
branch: 'main',
|
|
158
|
-
auth: {
|
|
159
|
-
access_token: process.env.GITHUB_TOKEN!,
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
false
|
|
164
|
-
);
|
|
165
|
-
```
|
|
107
|
+
### Files
|
|
166
108
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
The core class providing access to all development environment features.
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
class NotebookInstance {
|
|
173
|
-
// Core services
|
|
174
|
-
readonly file: Filesystem;
|
|
175
|
-
readonly terminal: Terminal;
|
|
176
|
-
readonly container: Container;
|
|
177
|
-
readonly lsp: Lsp;
|
|
178
|
-
readonly composer: Composer;
|
|
179
|
-
readonly git: Git;
|
|
180
|
-
readonly laravel: Laravel;
|
|
181
|
-
readonly repl: Repl;
|
|
182
|
-
readonly shell: Shell;
|
|
183
|
-
readonly auth: Auth;
|
|
184
|
-
readonly log: Log;
|
|
185
|
-
|
|
186
|
-
// Connection management
|
|
187
|
-
ready(): Promise<NotebookInitResult>;
|
|
188
|
-
connected(): Promise<NotebookInstance>;
|
|
189
|
-
reconnect(): void;
|
|
190
|
-
dispose(): void;
|
|
191
|
-
|
|
192
|
-
// Event handling
|
|
193
|
-
listen<T extends keyof Events>(event: T, handler: (data: Events[T]) => void): Disposable;
|
|
194
|
-
onDidConnect(handler: () => void): Disposable;
|
|
195
|
-
onDidDisconnect(handler: () => void): Disposable;
|
|
196
|
-
|
|
197
|
-
// Direct API calls
|
|
198
|
-
invoke<T extends keyof Invokable>(
|
|
199
|
-
action: T,
|
|
200
|
-
data?: Invokable[T]['args'],
|
|
201
|
-
options?: CallOption
|
|
202
|
-
): Promise<Invokable[T]['response']>;
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Filesystem
|
|
207
|
-
|
|
208
|
-
Comprehensive file system operations with advanced search and monitoring capabilities.
|
|
209
|
-
|
|
210
|
-
```typescript
|
|
211
|
-
class Filesystem {
|
|
212
|
-
// File operations
|
|
213
|
-
readFile(path: string, lineRange?: { lineStart: number; lineEnd: number }): Promise<Uint8Array | ReadFileRangeResult>;
|
|
214
|
-
writeFile(path: string, contents: Uint8Array, options: FileWriteOptions): Promise<void>;
|
|
215
|
-
info(path: string): Promise<FileInfo>;
|
|
216
|
-
stat(path: string): Promise<Stats>;
|
|
217
|
-
exists(path: string): Promise<boolean>;
|
|
218
|
-
|
|
219
|
-
// Directory operations
|
|
220
|
-
createDirectory(path: string): Promise<void>;
|
|
221
|
-
readDirectory(path: string, include?: string[], exclude?: string[]): Promise<[string, FileType, number | null][]>;
|
|
222
|
-
|
|
223
|
-
// File management
|
|
224
|
-
copy(source: string, destination: string, options: FileOverwriteOptions): Promise<void>;
|
|
225
|
-
move(from: string, to: string): Promise<boolean>;
|
|
226
|
-
rename(from: string, to: string, options: FileOverwriteOptions): Promise<void>;
|
|
227
|
-
delete(path: string, options: FileDeleteOptions): Promise<void>;
|
|
228
|
-
|
|
229
|
-
// Search capabilities
|
|
230
|
-
find(query: string, options?: Partial<FileSearchOptions>): Promise<FileResult[]>;
|
|
231
|
-
search(
|
|
232
|
-
query: TextSearchQuery,
|
|
233
|
-
options?: Partial<TextSearchOptions>,
|
|
234
|
-
onMatch?: (result: TextSearchResult | false) => void
|
|
235
|
-
): Promise<[boolean, TextSearchMatch[]]>;
|
|
236
|
-
|
|
237
|
-
// File monitoring
|
|
238
|
-
watch(path: string, options: WatchOptions, onDidChange: (e: FileChange) => void): FilesystemSubscription;
|
|
239
|
-
|
|
240
|
-
// Bulk operations
|
|
241
|
-
download(chunk?: (data: Uint8Array) => void, exclude?: string[]): Promise<Blob>;
|
|
242
|
-
}
|
|
243
|
-
```
|
|
109
|
+
```ts
|
|
110
|
+
await notebook.file.write('README.md', '# App');
|
|
244
111
|
|
|
245
|
-
|
|
112
|
+
const raw = await notebook.file.readFile('README.md');
|
|
113
|
+
const text = new TextDecoder().decode(raw);
|
|
246
114
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const phpFiles = await notebook.file.find('*.php', {
|
|
250
|
-
includes: ['src/**'],
|
|
115
|
+
const files = await notebook.file.find('*.php', {
|
|
116
|
+
includes: ['app/**'],
|
|
251
117
|
excludes: ['vendor/**'],
|
|
252
|
-
useIgnoreFiles: true,
|
|
253
118
|
});
|
|
254
119
|
|
|
255
|
-
// Full-text search with context
|
|
256
120
|
const [hasMore, matches] = await notebook.file.search(
|
|
257
|
-
{ pattern: '
|
|
258
|
-
{ maxResults:
|
|
121
|
+
{ pattern: 'class\\s+User', isRegExp: true },
|
|
122
|
+
{ maxResults: 20, includes: ['app/**'], excludes: ['vendor/**'] }
|
|
259
123
|
);
|
|
260
124
|
```
|
|
261
125
|
|
|
262
126
|
### Terminal
|
|
263
127
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
class Terminal {
|
|
268
|
-
// Terminal management
|
|
269
|
-
create(input: TerminalCreateInput): Promise<Task>;
|
|
270
|
-
list(): Promise<Task[]>;
|
|
271
|
-
resize(id: string, size: [number, number]): Promise<boolean>;
|
|
272
|
-
input(id: string, input: string): Promise<void>;
|
|
273
|
-
|
|
274
|
-
// Process execution
|
|
275
|
-
spawn(command: string, args: string[], opts?: SpawnOptions): Promise<SandboxProcess & Task>;
|
|
276
|
-
|
|
277
|
-
// Event handling
|
|
278
|
-
onStarted(handler: (task: Task) => void): void;
|
|
279
|
-
onOutput(id: string, handler: (data: TerminalEvents['terminal.output']) => void): void;
|
|
280
|
-
listen<T extends keyof TerminalEvents>(event: T, handler: (data: TerminalEvents[T]) => void): Disposable;
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
#### Terminal Usage Example
|
|
128
|
+
```ts
|
|
129
|
+
const task = await notebook.terminal.spawn('composer', ['--version']);
|
|
285
130
|
|
|
286
|
-
|
|
287
|
-
// Spawn a process with I/O streams
|
|
288
|
-
const process = await notebook.terminal.spawn('composer', ['install'], {
|
|
289
|
-
cwd: '/app',
|
|
290
|
-
env: { COMPOSER_NO_INTERACTION: '1' },
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
// Handle output stream
|
|
294
|
-
const reader = process.output.getReader();
|
|
295
|
-
while (true) {
|
|
296
|
-
const { done, value } = await reader.read();
|
|
297
|
-
if (done) break;
|
|
131
|
+
task.output.getReader().read().then(({ value }) => {
|
|
298
132
|
console.log(value);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Wait for completion
|
|
302
|
-
const exitCode = await process.exit;
|
|
303
|
-
console.log(`Process exited with code: ${exitCode}`);
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Container
|
|
307
|
-
|
|
308
|
-
Container lifecycle and resource management.
|
|
309
|
-
|
|
310
|
-
```typescript
|
|
311
|
-
class Container {
|
|
312
|
-
// Container control
|
|
313
|
-
start(): Promise<void>;
|
|
314
|
-
stop(): Promise<void>;
|
|
315
|
-
state(): Promise<{ state: NotebookState }>;
|
|
316
|
-
|
|
317
|
-
// Port management
|
|
318
|
-
openedPorts(): Promise<PortInfo[]>;
|
|
319
|
-
onPort(handler: (port: PortInfo, type: 'open' | 'close') => void): Disposable;
|
|
320
|
-
|
|
321
|
-
// Environment configuration
|
|
322
|
-
setPhp(version: string): Promise<{ version: string }>;
|
|
133
|
+
});
|
|
323
134
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
135
|
+
const exitCode = await task.exit;
|
|
136
|
+
console.log(exitCode);
|
|
327
137
|
```
|
|
328
138
|
|
|
329
|
-
###
|
|
330
|
-
|
|
331
|
-
IDE-like features through Language Server Protocol integration.
|
|
332
|
-
|
|
333
|
-
```typescript
|
|
334
|
-
class Lsp {
|
|
335
|
-
// Connection management
|
|
336
|
-
connection(id: string): LspConnection;
|
|
337
|
-
start(id: string): Promise<void>;
|
|
338
|
-
close(id: string): Promise<void>;
|
|
339
|
-
|
|
340
|
-
// Communication
|
|
341
|
-
message(id: string, message: string): Promise<void>;
|
|
342
|
-
|
|
343
|
-
// Event handling
|
|
344
|
-
onResponse(id: string, cb: (data: string) => void): void;
|
|
345
|
-
onError(id: string, cb: (message: string) => void): void;
|
|
346
|
-
onClose(id: string, cb: (code: number, reason: string) => void): void;
|
|
347
|
-
}
|
|
139
|
+
### Shell
|
|
348
140
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
onClose(cb: (code: number, reason: string) => void): void;
|
|
354
|
-
start(): Promise<void>;
|
|
355
|
-
dispose(): void;
|
|
356
|
-
}
|
|
141
|
+
```ts
|
|
142
|
+
const result = await notebook.shell.exec('php -v');
|
|
143
|
+
result.throw();
|
|
144
|
+
console.log(result.output);
|
|
357
145
|
```
|
|
358
146
|
|
|
359
147
|
### Composer
|
|
360
148
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
class Composer {
|
|
365
|
-
// Package management
|
|
366
|
-
install(packages?: string[]): Promise<void>;
|
|
367
|
-
update(packages?: string[]): Promise<void>;
|
|
368
|
-
remove(packages: string[]): Promise<void>;
|
|
149
|
+
```ts
|
|
150
|
+
await notebook.composer.install({ noInteraction: true });
|
|
151
|
+
await notebook.composer.require({ packages: ['monolog/monolog'] });
|
|
369
152
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
validate(): Promise<void>;
|
|
373
|
-
|
|
374
|
-
// Information
|
|
375
|
-
show(package?: string): Promise<object>;
|
|
376
|
-
outdated(): Promise<object>;
|
|
377
|
-
|
|
378
|
-
// Event handling
|
|
379
|
-
listen<T extends keyof ComposerEvents>(event: T, handler: (data: ComposerEvents[T]) => void): Disposable;
|
|
380
|
-
}
|
|
153
|
+
const installed = await notebook.composer.packages();
|
|
154
|
+
console.log(installed.map((pkg) => pkg.name));
|
|
381
155
|
```
|
|
382
156
|
|
|
383
157
|
### Git
|
|
384
158
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
```typescript
|
|
388
|
-
class Git {
|
|
389
|
-
// Repository operations
|
|
390
|
-
init(): Promise<void>;
|
|
391
|
-
clone(url: string, directory?: string): Promise<void>;
|
|
392
|
-
|
|
393
|
-
// Branch management
|
|
394
|
-
branch(name?: string): Promise<string[] | void>;
|
|
395
|
-
checkout(branch: string): Promise<void>;
|
|
396
|
-
|
|
397
|
-
// Staging and commits
|
|
398
|
-
add(files: string[]): Promise<void>;
|
|
399
|
-
commit(message: string): Promise<void>;
|
|
400
|
-
push(remote?: string, branch?: string): Promise<void>;
|
|
401
|
-
pull(remote?: string, branch?: string): Promise<void>;
|
|
402
|
-
|
|
403
|
-
// Information
|
|
404
|
-
status(): Promise<GitStatus>;
|
|
405
|
-
log(options?: GitLogOptions): Promise<GitCommit[]>;
|
|
406
|
-
diff(options?: GitDiffOptions): Promise<string>;
|
|
407
|
-
|
|
408
|
-
// Event handling
|
|
409
|
-
listen<T extends keyof GitEvents>(event: T, handler: (data: GitEvents[T]) => void): Disposable;
|
|
410
|
-
}
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
### Laravel
|
|
414
|
-
|
|
415
|
-
Laravel-specific development tools and utilities.
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
class Laravel {
|
|
419
|
-
// Artisan commands
|
|
420
|
-
artisan(command: string, args?: string[]): Promise<void>
|
|
421
|
-
|
|
422
|
-
// Code generation
|
|
423
|
-
make(type: string, name: string, options?: object): Promise<void>
|
|
424
|
-
|
|
425
|
-
// Database operations
|
|
426
|
-
migrate(options?: MigrateOptions): Promise<void>
|
|
427
|
-
seed(class?: string): Promise<void>
|
|
428
|
-
|
|
429
|
-
// Cache management
|
|
430
|
-
cache(action: 'clear' | 'config' | 'route' | 'view'): Promise<void>
|
|
431
|
-
|
|
432
|
-
// Event handling
|
|
433
|
-
listen<T extends keyof LaravelEvents>(event: T, handler: (data: LaravelEvents[T]) => void): Disposable
|
|
434
|
-
}
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
### REPL
|
|
438
|
-
|
|
439
|
-
Interactive PHP execution environment.
|
|
440
|
-
|
|
441
|
-
```typescript
|
|
442
|
-
class Repl {
|
|
443
|
-
// Code execution
|
|
444
|
-
execute(code: string): Promise<ReplResult>;
|
|
159
|
+
```ts
|
|
160
|
+
await notebook.git.checkpoint('Jane Doe <jane@example.com>', 'Initial checkpoint');
|
|
445
161
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
listen<T extends keyof ReplEvents>(event: T, handler: (data: ReplEvents[T]) => void): Disposable;
|
|
454
|
-
}
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
### Shell
|
|
458
|
-
|
|
459
|
-
Shell command execution with customizable environments.
|
|
460
|
-
|
|
461
|
-
```typescript
|
|
462
|
-
class Shell {
|
|
463
|
-
// Command execution
|
|
464
|
-
execute(command: string, options?: ShellOptions): Promise<ShellResult>;
|
|
465
|
-
|
|
466
|
-
// Environment management
|
|
467
|
-
setEnv(variables: Record<string, string>): Promise<void>;
|
|
468
|
-
getEnv(): Promise<Record<string, string>>;
|
|
469
|
-
|
|
470
|
-
// Working directory
|
|
471
|
-
pwd(): Promise<string>;
|
|
472
|
-
cd(directory: string): Promise<void>;
|
|
473
|
-
|
|
474
|
-
// Event handling
|
|
475
|
-
listen<T extends keyof ShellEvents>(event: T, handler: (data: ShellEvents[T]) => void): Disposable;
|
|
476
|
-
}
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
### Auth
|
|
480
|
-
|
|
481
|
-
Authentication and authorization services.
|
|
482
|
-
|
|
483
|
-
```typescript
|
|
484
|
-
class Auth {
|
|
485
|
-
// Token management
|
|
486
|
-
login(credentials: LoginCredentials): Promise<AuthResult>;
|
|
487
|
-
logout(): Promise<void>;
|
|
488
|
-
refresh(): Promise<AuthResult>;
|
|
489
|
-
|
|
490
|
-
// User information
|
|
491
|
-
user(): Promise<User>;
|
|
492
|
-
|
|
493
|
-
// Permissions
|
|
494
|
-
can(permission: string): Promise<boolean>;
|
|
495
|
-
}
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
### Logging
|
|
499
|
-
|
|
500
|
-
Application logging and monitoring.
|
|
501
|
-
|
|
502
|
-
```typescript
|
|
503
|
-
class Log {
|
|
504
|
-
// Log levels
|
|
505
|
-
debug(message: string, context?: object): Promise<void>;
|
|
506
|
-
info(message: string, context?: object): Promise<void>;
|
|
507
|
-
warning(message: string, context?: object): Promise<void>;
|
|
508
|
-
error(message: string, context?: object): Promise<void>;
|
|
509
|
-
|
|
510
|
-
// Log retrieval
|
|
511
|
-
recent(limit?: number): Promise<LogEntry[]>;
|
|
512
|
-
search(query: string, options?: LogSearchOptions): Promise<LogEntry[]>;
|
|
162
|
+
await notebook.git.sync(
|
|
163
|
+
'https://github.com/acme/my-repo.git',
|
|
164
|
+
'Jane Doe <jane@example.com>',
|
|
165
|
+
'main',
|
|
166
|
+
process.env.GITHUB_TOKEN,
|
|
167
|
+
'pull'
|
|
168
|
+
);
|
|
513
169
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
}
|
|
170
|
+
const history = await notebook.git.log('main');
|
|
171
|
+
console.log(history[0]);
|
|
517
172
|
```
|
|
518
173
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
The SDK provides a comprehensive event system for real-time updates:
|
|
522
|
-
|
|
523
|
-
```typescript
|
|
524
|
-
// File system events
|
|
525
|
-
notebook.file.watch('/app', { recursive: true }, (change) => {
|
|
526
|
-
console.log(`File ${change.path} was ${change.type}`);
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
// Terminal output
|
|
530
|
-
notebook.terminal.onOutput('terminal-id', (data) => {
|
|
531
|
-
console.log(data.output);
|
|
532
|
-
});
|
|
174
|
+
### Events
|
|
533
175
|
|
|
534
|
-
|
|
535
|
-
notebook.
|
|
536
|
-
console.log(
|
|
176
|
+
```ts
|
|
177
|
+
const disposeConnect = notebook.onDidConnect(() => {
|
|
178
|
+
console.log('connected');
|
|
537
179
|
});
|
|
538
180
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
181
|
+
const disposeFs = notebook.file.watch(
|
|
182
|
+
'/app',
|
|
183
|
+
{ recursive: true, excludes: ['vendor/**', 'node_modules/**'] },
|
|
184
|
+
(change) => {
|
|
185
|
+
console.log(change.type, change.path);
|
|
186
|
+
}
|
|
187
|
+
);
|
|
543
188
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
189
|
+
// later
|
|
190
|
+
disposeConnect.dispose();
|
|
191
|
+
disposeFs.dispose();
|
|
547
192
|
```
|
|
548
193
|
|
|
549
194
|
## Error Handling
|
|
550
195
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
```typescript
|
|
554
|
-
import { FilesystemError, FilesystemErrorType, ErrorEvent } from '@phpsandbox/sdk';
|
|
196
|
+
```ts
|
|
197
|
+
import { ApiError, FilesystemError, FilesystemErrorType } from '@phpsandbox/sdk';
|
|
555
198
|
|
|
556
199
|
try {
|
|
557
|
-
await notebook.file.readFile('/
|
|
200
|
+
await notebook.file.readFile('/does-not-exist.php');
|
|
558
201
|
} catch (error) {
|
|
559
202
|
if (error instanceof FilesystemError && error.name === FilesystemErrorType.FileNotFound) {
|
|
560
|
-
console.
|
|
561
|
-
} else if (error instanceof
|
|
562
|
-
console.
|
|
203
|
+
console.error('Missing file');
|
|
204
|
+
} else if (error instanceof ApiError) {
|
|
205
|
+
console.error(error.status, error.body);
|
|
206
|
+
} else {
|
|
207
|
+
throw error;
|
|
563
208
|
}
|
|
564
209
|
}
|
|
565
210
|
```
|
|
566
211
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
- `FilesystemError`: File system operation errors
|
|
570
|
-
- `RateLimitError`: API rate limiting
|
|
571
|
-
- `NotebookInitError`: Notebook initialization failures
|
|
572
|
-
- `ErrorEvent`: Base error class with error codes
|
|
212
|
+
## Browser/CDN Usage
|
|
573
213
|
|
|
574
|
-
|
|
214
|
+
See `docs/cdn-usage.md` for ESM and script-tag examples.
|
|
575
215
|
|
|
576
|
-
|
|
216
|
+
## More Docs
|
|
577
217
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
async function setupLaravelApp() {
|
|
582
|
-
const client = new PHPSandbox(process.env.PHPSANDBOX_TOKEN);
|
|
583
|
-
const notebook = await client.notebook.create('laravel');
|
|
584
|
-
|
|
585
|
-
// Wait for container to be ready
|
|
586
|
-
await notebook.ready();
|
|
587
|
-
|
|
588
|
-
// Install additional dependencies
|
|
589
|
-
await notebook.composer.install(['laravel/sanctum', 'laravel/horizon']);
|
|
590
|
-
|
|
591
|
-
// Create a new controller
|
|
592
|
-
await notebook.laravel.make('controller', 'ApiController', { resource: true });
|
|
593
|
-
|
|
594
|
-
// Run migrations
|
|
595
|
-
await notebook.laravel.migrate();
|
|
596
|
-
|
|
597
|
-
// Set up Git repository
|
|
598
|
-
await notebook.git.init();
|
|
599
|
-
await notebook.git.add(['.']);
|
|
600
|
-
await notebook.git.commit('Initial commit');
|
|
601
|
-
|
|
602
|
-
// Start development server
|
|
603
|
-
const server = await notebook.terminal.spawn('php', ['artisan', 'serve', '--host=0.0.0.0']);
|
|
604
|
-
|
|
605
|
-
// Monitor for open ports
|
|
606
|
-
notebook.container.onPort((port, type) => {
|
|
607
|
-
if (type === 'open' && port.port === 8000) {
|
|
608
|
-
console.log(`Laravel server available at: ${port.url}`);
|
|
609
|
-
}
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
return notebook;
|
|
613
|
-
}
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
### File Processing Pipeline
|
|
617
|
-
|
|
618
|
-
```typescript
|
|
619
|
-
async function processPhpFiles(notebook: NotebookInstance) {
|
|
620
|
-
// Find all PHP files
|
|
621
|
-
const phpFiles = await notebook.file.find('*.php', {
|
|
622
|
-
includes: ['app/**', 'src/**'],
|
|
623
|
-
excludes: ['vendor/**', 'node_modules/**'],
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
// Process each file
|
|
627
|
-
for (const file of phpFiles) {
|
|
628
|
-
const content = await notebook.file.readFile(file.path);
|
|
629
|
-
|
|
630
|
-
// Run PHP CS Fixer
|
|
631
|
-
await notebook.terminal.spawn('php-cs-fixer', ['fix', file.path]);
|
|
632
|
-
|
|
633
|
-
// Run static analysis
|
|
634
|
-
const analysis = await notebook.terminal.spawn('phpstan', ['analyse', file.path]);
|
|
635
|
-
|
|
636
|
-
// Wait for completion
|
|
637
|
-
await analysis.exit;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
console.log(`Processed ${phpFiles.length} PHP files`);
|
|
641
|
-
}
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
### Real-time Development Environment
|
|
645
|
-
|
|
646
|
-
```typescript
|
|
647
|
-
async function createDevelopmentEnvironment() {
|
|
648
|
-
const client = new PHPSandbox(process.env.PHPSANDBOX_TOKEN);
|
|
649
|
-
const notebook = await client.notebook.create('php');
|
|
650
|
-
|
|
651
|
-
// Set up file watching
|
|
652
|
-
notebook.file.watch('/app', { recursive: true }, (change) => {
|
|
653
|
-
console.log(`[${new Date().toISOString()}] ${change.path} ${change.type}`);
|
|
654
|
-
|
|
655
|
-
// Auto-reload on PHP file changes
|
|
656
|
-
if (change.path.endsWith('.php') && change.type === 'UPDATED') {
|
|
657
|
-
notebook.repl.execute(`include '${change.path}';`);
|
|
658
|
-
}
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
// Set up LSP for IDE features
|
|
662
|
-
const lspConnection = notebook.lsp.connection('php-lsp');
|
|
663
|
-
await lspConnection.start();
|
|
664
|
-
|
|
665
|
-
lspConnection.onMessage((message) => {
|
|
666
|
-
const data = JSON.parse(message);
|
|
667
|
-
if (data.method === 'textDocument/publishDiagnostics') {
|
|
668
|
-
console.log('Diagnostics:', data.params.diagnostics);
|
|
669
|
-
}
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
// Monitor container resources
|
|
673
|
-
notebook.container.listen('container.stats', (stats) => {
|
|
674
|
-
if (stats.memory.usage / stats.memory.limit > 0.8) {
|
|
675
|
-
console.warn('High memory usage detected');
|
|
676
|
-
}
|
|
677
|
-
});
|
|
678
|
-
|
|
679
|
-
return notebook;
|
|
680
|
-
}
|
|
681
|
-
```
|
|
682
|
-
|
|
683
|
-
## TypeScript Support
|
|
684
|
-
|
|
685
|
-
The SDK is built with TypeScript and provides comprehensive type definitions:
|
|
686
|
-
|
|
687
|
-
```typescript
|
|
688
|
-
import type {
|
|
689
|
-
NotebookInstance,
|
|
690
|
-
FileInfo,
|
|
691
|
-
Stats,
|
|
692
|
-
TextSearchQuery,
|
|
693
|
-
TerminalCreateInput,
|
|
694
|
-
ContainerStats,
|
|
695
|
-
Events,
|
|
696
|
-
FilesystemEvents,
|
|
697
|
-
} from '@phpsandbox/sdk';
|
|
698
|
-
|
|
699
|
-
// Type-safe event handling
|
|
700
|
-
notebook.listen('fs.watch', (change: Events['fs.watch']) => {
|
|
701
|
-
// change is properly typed as FileChange
|
|
702
|
-
console.log(change.path, change.type);
|
|
703
|
-
});
|
|
704
|
-
|
|
705
|
-
// Type-safe API calls
|
|
706
|
-
const stats: Stats = await notebook.file.stat('/app/composer.json');
|
|
707
|
-
const info: FileInfo = await notebook.file.info('/app/index.php');
|
|
708
|
-
```
|
|
709
|
-
|
|
710
|
-
### Generic Types
|
|
711
|
-
|
|
712
|
-
```typescript
|
|
713
|
-
// Custom event handlers
|
|
714
|
-
type CustomEventHandler<T extends keyof Events> = (data: Events[T]) => void;
|
|
715
|
-
|
|
716
|
-
// Action types
|
|
717
|
-
type FileSystemActions = FilesystemActions;
|
|
718
|
-
type TerminalActions = TerminalActions;
|
|
719
|
-
|
|
720
|
-
// Disposable pattern
|
|
721
|
-
const disposable: Disposable = notebook.onDidConnect(() => {
|
|
722
|
-
console.log('Connected');
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
// Clean up when done
|
|
726
|
-
disposable.dispose();
|
|
727
|
-
```
|
|
218
|
+
- Getting started walkthrough: `docs/getting-started.md`
|
|
219
|
+
- API overview: `docs/api-summary.md`
|
|
220
|
+
- Examples: `examples/README.md`
|
|
728
221
|
|
|
729
|
-
## Support
|
|
222
|
+
## Support
|
|
730
223
|
|
|
731
|
-
-
|
|
732
|
-
-
|
|
733
|
-
- **Issues**: [GitHub Issues](https://github.com/phpsandbox/sdk/issues)
|
|
734
|
-
- **Examples**: [GitHub Examples](https://github.com/phpsandbox/examples)
|
|
224
|
+
- Issues: https://github.com/phpsandbox/sdk/issues
|
|
225
|
+
- Product docs: https://docs.phpsandbox.io
|
|
735
226
|
|
|
736
227
|
## License
|
|
737
228
|
|
|
738
|
-
MIT
|
|
229
|
+
MIT
|