@phpsandbox/sdk 0.0.68 → 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.
Files changed (56) hide show
  1. package/README.md +66 -32
  2. package/dist/auth.d.ts +0 -1
  3. package/dist/auth.js +0 -3
  4. package/dist/beacon/index.d.ts +2 -0
  5. package/dist/beacon/index.js +5 -0
  6. package/dist/browser/phpsandbox-sdk.esm.js +842 -1320
  7. package/dist/browser/phpsandbox-sdk.esm.min.js +24 -24
  8. package/dist/browser/phpsandbox-sdk.iife.js +842 -1320
  9. package/dist/browser/phpsandbox-sdk.iife.min.js +23 -23
  10. package/dist/composer.d.ts +36 -23
  11. package/dist/composer.js +61 -11
  12. package/dist/container.d.ts +2 -6
  13. package/dist/container.js +0 -28
  14. package/dist/filesystem.d.ts +58 -17
  15. package/dist/filesystem.js +169 -51
  16. package/dist/index.d.ts +30 -26
  17. package/dist/index.js +37 -32
  18. package/dist/log.d.ts +11 -5
  19. package/dist/log.js +10 -7
  20. package/dist/metrics.d.ts +10 -0
  21. package/dist/metrics.js +13 -0
  22. package/dist/ports.d.ts +10 -0
  23. package/dist/ports.js +13 -0
  24. package/dist/publications.d.ts +222 -0
  25. package/dist/{deployments.js → publications.js} +64 -69
  26. package/dist/repl.d.ts +0 -2
  27. package/dist/repl.js +0 -3
  28. package/dist/runtime/rest.js +1 -4
  29. package/dist/runtime-telemetry.d.ts +15 -0
  30. package/dist/runtime-telemetry.js +111 -0
  31. package/dist/schemas/{deployments.d.ts → publications.d.ts} +76 -76
  32. package/dist/schemas/publications.js +133 -0
  33. package/dist/services.d.ts +2 -9
  34. package/dist/services.js +3 -10
  35. package/dist/shell.d.ts +52 -22
  36. package/dist/shell.js +103 -75
  37. package/dist/terminal.d.ts +18 -14
  38. package/dist/terminal.js +29 -49
  39. package/docs/api-summary.md +37 -29
  40. package/docs/cdn-usage.md +4 -4
  41. package/docs/getting-started.md +17 -17
  42. package/examples/README.md +8 -9
  43. package/examples/basic.ts +2 -2
  44. package/examples/git-merge-smoke.ts +3 -6
  45. package/examples/laravel-load-test.ts +80 -98
  46. package/examples/notebook-readonly-smoke.ts +38 -41
  47. package/examples/publication-provider-label.ts +11 -0
  48. package/examples/{deploy-cloudflare-container.ts → publish-cloudflare-container.ts} +11 -11
  49. package/examples/{deploy-laravel-cloud.ts → publish-laravel-cloud.ts} +11 -11
  50. package/examples/{deploy-ssh-agent.ts → publish-ssh-agent.ts} +15 -16
  51. package/package.json +7 -2
  52. package/dist/deployments.d.ts +0 -251
  53. package/dist/laravel.d.ts +0 -22
  54. package/dist/laravel.js +0 -11
  55. package/dist/schemas/deployments.js +0 -133
  56. package/examples/deployment-provider-label.ts +0 -11
package/README.md CHANGED
@@ -23,9 +23,9 @@ const client = PHPSandbox.realtime(token);
23
23
  // create() initializes the notebook by default
24
24
  const notebook = await client.notebook.create('php');
25
25
 
26
- await notebook.file.write('index.php', '<?php echo "Hello from PHPSandbox";');
26
+ await notebook.files.write('index.php', '<?php echo "Hello from PHPSandbox";');
27
27
 
28
- const process = await notebook.terminal.spawn('php', ['index.php']);
28
+ const process = await notebook.terminals.create({ command: 'php', args: ['index.php'] });
29
29
 
30
30
  const reader = process.output.getReader();
31
31
  let output = '';
@@ -39,7 +39,7 @@ try {
39
39
  reader.releaseLock();
40
40
  }
41
41
 
42
- await process.exit;
42
+ await process.wait();
43
43
  console.log(output.trim());
44
44
 
45
45
  // close websocket resources when done
@@ -76,14 +76,11 @@ PHPSandbox.rest('token', 'https://api.phpsandbox.io/v1', {
76
76
  const client = PHPSandbox.realtime(process.env.PHPSANDBOX_TOKEN!);
77
77
 
78
78
  const created = await client.notebook.create('laravel');
79
- const opened = await client.notebook.open('notebook-id');
80
- await opened.ready();
81
-
82
79
  const fetched = await client.notebook.get('notebook-id');
83
80
  await fetched.ready();
84
81
 
85
82
  const forked = await created.fork();
86
- await forked.delete();
83
+ await forked.destroy();
87
84
 
88
85
  const persistent = await client.notebook.create('laravel', {
89
86
  title: 'Persistent Laravel',
@@ -101,50 +98,58 @@ console.log(persistentFork.data.policy);
101
98
  Notes:
102
99
 
103
100
  - `create()` and `fork()` initialize automatically.
104
- - `open()` and `get()` return a notebook instance; call `await notebook.ready()` before using tools.
101
+ - `get()` returns a notebook instance; call `await notebook.ready()` before using tools.
105
102
  - API notebook creates and forks are ephemeral by default. `persistent: true` requires an entitled account.
106
- - Use `NotebookData.runtimeUrl`, `runtimeUrlProvider`, and `DeploymentData.eventStreamUrl` for runtime access.
103
+ - Use `NotebookData.runtimeUrl`, `runtimeUrlProvider`, and `PublicationData.eventStreamUrl` for runtime access.
107
104
 
108
105
  ## Services At A Glance
109
106
 
110
107
  Each `NotebookInstance` exposes service clients:
111
108
 
112
- - `notebook.file` (`Filesystem`)
113
- - `notebook.terminal` (`Terminal`)
109
+ - `notebook.files` (`Filesystem`)
110
+ - `notebook.terminals` (`Terminals`)
114
111
  - `notebook.container` (`Container`)
115
- - `notebook.shell` (`Shell`)
116
112
  - `notebook.composer` (`Composer`)
117
113
  - `notebook.git` (`Git`)
118
114
  - `notebook.lsp` (`Lsp`)
119
115
  - `notebook.repl` (`Repl`)
120
- - `notebook.laravel` (`Laravel`)
121
116
  - `notebook.auth` (`Auth`)
122
- - `notebook.log` (`Log`)
117
+ - `notebook.logs` (`Logs`)
118
+ - `notebook.ports` (`Ports`)
119
+ - `notebook.metrics` (`Metrics`)
123
120
  - `notebook.services` (`Services`)
124
121
  - `notebook.mail` (`NotebookMail`)
125
122
 
126
123
  Notes:
127
124
 
128
- - `terminal.spawn()` and `shell.exec()` are part of the current runtime action set. `terminal.start` currently is not.
129
- - `notebook.repl.eval()` is part of the current runtime action set. `repl.start` is currently not.
130
- - `notebook.laravel` is exposed by the SDK, but the current runtime action set does not expose Laravel maintenance actions.
125
+ - `terminals.create()` is the TTY-oriented process API; `notebook.exec()` and `notebook.run()` are the native non-TTY process APIs.
126
+ - `notebook.repl.eval()` evaluates PHP without exposing the unsupported `repl.start` action.
131
127
 
132
128
  ## Common Operations
133
129
 
134
130
  ### Files
135
131
 
136
132
  ```ts
137
- await notebook.file.write('README.md', '# App');
133
+ await notebook.files.write('README.md', '# App');
138
134
 
139
- const raw = await notebook.file.readFile('README.md');
140
- const text = new TextDecoder().decode(raw);
135
+ await notebook.files.write('archive.zip', byteStream);
136
+ for await (const chunk of notebook.files.readStream('archive.zip')) {
137
+ consume(chunk);
138
+ }
141
139
 
142
- const files = await notebook.file.find('*.php', {
140
+ const raw = await notebook.files.read('README.md');
141
+ const text = await notebook.files.readText('README.md');
142
+ const excerpt = await notebook.files.readLines('storage/logs/laravel.log', {
143
+ start: 100,
144
+ end: 200,
145
+ });
146
+
147
+ const files = await notebook.files.find('*.php', {
143
148
  includes: ['app/**'],
144
149
  excludes: ['vendor/**'],
145
150
  });
146
151
 
147
- const [hasMore, matches] = await notebook.file.search(
152
+ const [hasMore, matches] = await notebook.files.search(
148
153
  { pattern: 'class\\s+User', isRegExp: true },
149
154
  { maxResults: 20, includes: ['app/**'], excludes: ['vendor/**'] }
150
155
  );
@@ -153,22 +158,27 @@ const [hasMore, matches] = await notebook.file.search(
153
158
  ### Terminal
154
159
 
155
160
  ```ts
156
- const task = await notebook.terminal.spawn('composer', ['--version']);
161
+ const task = await notebook.terminals.create({ command: 'composer', args: ['--version'] });
157
162
 
158
163
  task.output.getReader().read().then(({ value }) => {
159
164
  console.log(value);
160
165
  });
161
166
 
162
- const exitCode = await task.exit;
167
+ const exitCode = await task.wait();
163
168
  console.log(exitCode);
164
169
  ```
165
170
 
166
171
  ### Shell
167
172
 
168
173
  ```ts
169
- const result = await notebook.shell.exec('php -v');
174
+ const result = await notebook.exec('php -v');
170
175
  result.throw();
171
- console.log(result.output);
176
+
177
+ const process = notebook.run('php -v', { tty: false });
178
+ for await (const chunk of process.output) {
179
+ console.log(chunk.source, new TextDecoder().decode(chunk.data));
180
+ }
181
+ (await process.wait()).throw();
172
182
  ```
173
183
 
174
184
  ### Services
@@ -187,17 +197,41 @@ const snapshot = await notebook.services.logs('redis', { tail: 50 });
187
197
  console.log(snapshot);
188
198
 
189
199
  const stream = notebook.services.logs('redis', { follow: true, tail: 25 });
190
- const reader = stream.output.getReader();
200
+ const reader = stream.getReader();
191
201
  const chunk = await reader.read();
192
202
  console.log(chunk.value);
193
- await stream.stop();
203
+ await reader.cancel();
204
+ ```
205
+
206
+ ### Runtime observability
207
+
208
+ ```ts
209
+ const currentPorts = await notebook.ports.list();
210
+ const currentMetrics = await notebook.metrics.current();
211
+
212
+ for await (const sample of notebook.metrics.watch({ signal })) {
213
+ console.log(sample.cpu, sample.memory, sample.disk);
214
+ }
215
+
216
+ for await (const ports of notebook.ports.watch({ signal })) {
217
+ console.log(ports);
218
+ }
219
+
220
+ for await (const entry of notebook.logs.follow({ signal })) {
221
+ console.log(entry.timestamp, entry.source, entry.message);
222
+ }
194
223
  ```
195
224
 
196
225
  ### Composer
197
226
 
198
227
  ```ts
199
- await notebook.composer.install({ noInteraction: true });
200
- await notebook.composer.require({ packages: ['monolog/monolog'] });
228
+ const install = notebook.composer.install();
229
+ for await (const chunk of install.output) {
230
+ console.log(chunk.source, new TextDecoder().decode(chunk.data));
231
+ }
232
+ (await install.wait()).throw();
233
+
234
+ (await notebook.composer.require({ packages: ['monolog/monolog'] }).wait()).throw();
201
235
 
202
236
  const installed = await notebook.composer.packages();
203
237
  console.log(installed.map((pkg) => pkg.name));
@@ -279,7 +313,7 @@ const disposeConnect = notebook.onDidConnect(() => {
279
313
  console.log('connected');
280
314
  });
281
315
 
282
- const disposeFs = notebook.file.watch(
316
+ const disposeFs = notebook.files.watch(
283
317
  '/app',
284
318
  { recursive: true, excludes: ['vendor/**', 'node_modules/**'] },
285
319
  (change) => {
@@ -298,7 +332,7 @@ disposeFs.dispose();
298
332
  import { ApiError, FilesystemError, FilesystemErrorType } from '@phpsandbox/sdk';
299
333
 
300
334
  try {
301
- await notebook.file.readFile('/does-not-exist.php');
335
+ await notebook.files.read('/does-not-exist.php');
302
336
  } catch (error) {
303
337
  if (error instanceof FilesystemError && error.name === FilesystemErrorType.FileNotFound) {
304
338
  console.error('Missing file');
package/dist/auth.d.ts CHANGED
@@ -7,6 +7,5 @@ export interface AuthActions {
7
7
  export default class Auth {
8
8
  protected okra: NotebookInstance;
9
9
  constructor(okra: NotebookInstance);
10
- logout(): void;
11
10
  login(runtimeUrl: string): Promise<boolean>;
12
11
  }
package/dist/auth.js CHANGED
@@ -2,9 +2,6 @@ export default class Auth {
2
2
  constructor(okra) {
3
3
  this.okra = okra;
4
4
  }
5
- logout() {
6
- this.okra.dispose();
7
- }
8
5
  login(runtimeUrl) {
9
6
  const runtimeTicket = new URL(runtimeUrl).searchParams.get('ticket');
10
7
  if (runtimeTicket === null || runtimeTicket === '') {
@@ -1,6 +1,7 @@
1
1
  import { Disposable } from '../types.js';
2
2
  import { BeaconActions, BeaconEvents, BeaconOptions, DebugInfo, ConsoleEvent, BeaconErrorEvent, DebugRequest, DebugResult, ScreenshotRequest, ScreenshotResult, FetchRequest, FetchResult } from './types.js';
3
3
  import { Navigator } from './navigator.js';
4
+ import type { NotebookInstance } from '../index.js';
4
5
  export * from './types.js';
5
6
  export { Navigator } from './navigator.js';
6
7
  /**
@@ -166,6 +167,7 @@ export declare class Beacon implements BeaconActions {
166
167
  * Factory function to create a beacon instance for an iframe
167
168
  */
168
169
  export declare function createBeacon(iframe: HTMLIFrameElement, options?: BeaconOptions): Beacon;
170
+ export declare function connectBeacon(notebook: NotebookInstance, iframe: HTMLIFrameElement, options?: BeaconOptions): Promise<Beacon>;
169
171
  /**
170
172
  * Check if the current environment supports the Beacon SDK
171
173
  */
@@ -530,6 +530,11 @@ export class Beacon {
530
530
  export function createBeacon(iframe, options) {
531
531
  return new Beacon(iframe, options);
532
532
  }
533
+ export async function connectBeacon(notebook, iframe, options) {
534
+ const result = await notebook.ready();
535
+ iframe.src = result.data.previewUrl;
536
+ return createBeacon(iframe, options);
537
+ }
533
538
  /**
534
539
  * Check if the current environment supports the Beacon SDK
535
540
  */