@phpsandbox/sdk 0.1.6 → 0.1.10
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 +42 -50
- package/dist/beacon/index.d.ts +1 -7
- package/dist/beacon/index.js +14 -13
- package/dist/beacon/navigator.d.ts +8 -36
- package/dist/beacon/navigator.js +1 -62
- package/dist/browser/phpsandbox-sdk.esm.js +547 -691
- package/dist/browser/phpsandbox-sdk.esm.min.js +23 -23
- package/dist/browser/phpsandbox-sdk.iife.js +547 -691
- package/dist/browser/phpsandbox-sdk.iife.min.js +35 -35
- package/dist/composer.d.ts +10 -8
- package/dist/composer.js +18 -18
- package/dist/errors/index.d.ts +43 -8
- package/dist/errors/index.js +120 -14
- package/dist/feedback.js +1 -2
- package/dist/filesystem.d.ts +0 -17
- package/dist/filesystem.js +2 -21
- package/dist/git.d.ts +1 -5
- package/dist/git.js +6 -8
- package/dist/index.d.ts +66 -156
- package/dist/index.js +172 -289
- package/dist/integrations.d.ts +0 -2
- package/dist/integrations.js +5 -11
- package/dist/log.d.ts +0 -2
- package/dist/lsp.js +1 -1
- package/dist/metrics.d.ts +3 -3
- package/dist/ports.d.ts +1 -1
- package/dist/publications.d.ts +4 -54
- package/dist/publications.js +25 -103
- package/dist/runtime/rest.js +34 -17
- package/dist/runtime.d.ts +68 -0
- package/dist/runtime.js +46 -0
- package/dist/sandbox-integrations.d.ts +1 -2
- package/dist/sandbox-integrations.js +11 -14
- package/dist/schemas/publications.d.ts +0 -6
- package/dist/schemas/publications.js +0 -1
- package/dist/servers.d.ts +4 -2
- package/dist/servers.js +5 -8
- package/dist/shell.d.ts +2 -14
- package/dist/shell.js +1 -21
- package/dist/socket/index.d.ts +6 -7
- package/dist/socket/index.js +39 -25
- package/dist/types.d.ts +0 -12
- package/dist/types.js +1 -15
- package/docs/api-summary.md +28 -28
- package/docs/cdn-usage.md +43 -55
- package/docs/getting-started.md +43 -26
- package/examples/README.md +5 -35
- package/examples/basic.ts +9 -18
- package/examples/get.ts +2 -2
- package/examples/git-merge-smoke.ts +2 -3
- package/examples/laravel-load-test.ts +31 -36
- package/examples/notebook-readonly-smoke.ts +12 -26
- package/examples/publication-provider-label.ts +1 -1
- package/examples/publish-cloudflare-container.ts +2 -2
- package/examples/publish-laravel-cloud.ts +2 -2
- package/examples/publish-ssh-agent.ts +2 -2
- package/package.json +4 -3
- package/dist/container.d.ts +0 -65
- package/dist/container.js +0 -30
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@ Node.js `>=18` is required. This package is ESM-only; use `import` rather than `
|
|
|
12
12
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
15
|
+
Save this as `quickstart.mjs` and run `node quickstart.mjs` after setting `PHPSANDBOX_TOKEN`. Expected output: `Hello from PHPSandbox`. The example creates and deletes a temporary plain PHP notebook.
|
|
16
|
+
|
|
15
17
|
```ts
|
|
16
18
|
import { PHPSandbox } from '@phpsandbox/sdk';
|
|
17
19
|
|
|
@@ -19,36 +21,24 @@ const token = process.env.PHPSANDBOX_TOKEN;
|
|
|
19
21
|
if (!token) throw new Error('Missing PHPSANDBOX_TOKEN');
|
|
20
22
|
|
|
21
23
|
const client = PHPSandbox.realtime(token);
|
|
24
|
+
const notebook = await client.notebook.create('standard');
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const process = await notebook.terminals.create({ command: 'php', args: ['index.php'] });
|
|
29
|
-
|
|
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
|
-
}
|
|
41
|
-
|
|
42
|
-
await process.wait();
|
|
43
|
-
console.log(output.trim());
|
|
26
|
+
await notebook.files.write('hello.php', '<?php echo "Hello from PHPSandbox";');
|
|
27
|
+
const result = await notebook.exec('php', ['hello.php']);
|
|
28
|
+
if (result.exitCode !== 0) throw new Error(result.stderr || result.output);
|
|
29
|
+
console.log(result.stdout.trim());
|
|
44
30
|
|
|
45
|
-
|
|
31
|
+
await notebook.destroy();
|
|
46
32
|
notebook.dispose();
|
|
47
33
|
```
|
|
48
34
|
|
|
49
35
|
## Authentication
|
|
50
36
|
|
|
51
|
-
|
|
37
|
+
Sign in to PHPSandbox and open **API keys**. Create a named key and copy it when shown; it cannot be revealed again. API-key access currently requires SDK access to be enabled for your account. Creating or forking notebooks requires an active subscription and available notebook capacity.
|
|
38
|
+
|
|
39
|
+
Keys from this screen grant account-level notebook read and write access. Keep them in a server environment variable or secret store. Never place them in browser code, notebooks, URLs, logs, or source control. To rotate, create a replacement, update your application, verify it, then revoke the old key.
|
|
40
|
+
|
|
41
|
+
Use an API key:
|
|
52
42
|
|
|
53
43
|
```ts
|
|
54
44
|
import { PHPSandbox } from '@phpsandbox/sdk';
|
|
@@ -61,7 +51,6 @@ Explicit realtime and REST clients:
|
|
|
61
51
|
```ts
|
|
62
52
|
PHPSandbox.realtime('token', 'https://api.phpsandbox.io/v1', {
|
|
63
53
|
debug: false,
|
|
64
|
-
startClosed: true,
|
|
65
54
|
});
|
|
66
55
|
|
|
67
56
|
// Use explicit request/response runtime actions without a websocket.
|
|
@@ -77,7 +66,6 @@ const client = PHPSandbox.realtime(process.env.PHPSANDBOX_TOKEN!);
|
|
|
77
66
|
|
|
78
67
|
const created = await client.notebook.create('laravel');
|
|
79
68
|
const fetched = await client.notebook.get('notebook-id');
|
|
80
|
-
await fetched.ready();
|
|
81
69
|
|
|
82
70
|
const forked = await created.fork();
|
|
83
71
|
await forked.destroy();
|
|
@@ -97,8 +85,8 @@ console.log(persistentFork.data.policy);
|
|
|
97
85
|
|
|
98
86
|
Notes:
|
|
99
87
|
|
|
100
|
-
-
|
|
101
|
-
- `
|
|
88
|
+
- Runtime actions wait for the sandbox to become ready before Okra handles them.
|
|
89
|
+
- Call `ready()` explicitly only when you need provisioning results such as the preview URL or opened ports.
|
|
102
90
|
- API notebook creates and forks are ephemeral by default. `persistent: true` requires an entitled account.
|
|
103
91
|
- Use `NotebookData.runtimeUrl`, `runtimeUrlProvider`, and `PublicationData.eventStreamUrl` for runtime access.
|
|
104
92
|
|
|
@@ -108,16 +96,13 @@ Each `NotebookInstance` exposes service clients:
|
|
|
108
96
|
|
|
109
97
|
- `notebook.files` (`Filesystem`)
|
|
110
98
|
- `notebook.terminals` (`Terminals`)
|
|
111
|
-
- `notebook.
|
|
99
|
+
- `notebook.runtime` (lifecycle, configuration, logs, metrics, and ports)
|
|
112
100
|
- `notebook.composer` (`Composer`)
|
|
113
101
|
- `notebook.git` (`Git`)
|
|
114
102
|
- `notebook.integrations` (`SandboxIntegrationApi`)
|
|
115
103
|
- `notebook.lsp` (`Lsp`)
|
|
116
104
|
- `notebook.repl` (`Repl`)
|
|
117
105
|
- `notebook.auth` (`Auth`)
|
|
118
|
-
- `notebook.logs` (`Logs`)
|
|
119
|
-
- `notebook.ports` (`Ports`)
|
|
120
|
-
- `notebook.metrics` (`Metrics`)
|
|
121
106
|
- `notebook.services` (`Services`)
|
|
122
107
|
- `notebook.mail` (`NotebookMail`)
|
|
123
108
|
- `notebook.feedback` (`Feedback`)
|
|
@@ -174,13 +159,14 @@ console.log(exitCode);
|
|
|
174
159
|
|
|
175
160
|
```ts
|
|
176
161
|
const result = await notebook.exec('php -v');
|
|
177
|
-
result.throw();
|
|
162
|
+
if (result.exitCode !== 0) throw new Error(result.stderr || result.output);
|
|
178
163
|
|
|
179
164
|
const process = notebook.run('php -v', { tty: false });
|
|
180
165
|
for await (const chunk of process.output) {
|
|
181
166
|
console.log(chunk.source, new TextDecoder().decode(chunk.data));
|
|
182
167
|
}
|
|
183
|
-
|
|
168
|
+
const processResult = await process.wait();
|
|
169
|
+
if (processResult.exitCode !== 0) throw new Error(processResult.stderr || processResult.output);
|
|
184
170
|
```
|
|
185
171
|
|
|
186
172
|
### Services
|
|
@@ -208,18 +194,18 @@ await reader.cancel();
|
|
|
208
194
|
### Runtime observability
|
|
209
195
|
|
|
210
196
|
```ts
|
|
211
|
-
const currentPorts = await notebook.ports.list();
|
|
212
|
-
const currentMetrics = await notebook.metrics.current();
|
|
197
|
+
const currentPorts = await notebook.runtime.ports.list();
|
|
198
|
+
const currentMetrics = await notebook.runtime.metrics.current();
|
|
213
199
|
|
|
214
|
-
for await (const sample of notebook.metrics.watch({ signal })) {
|
|
200
|
+
for await (const sample of notebook.runtime.metrics.watch({ signal })) {
|
|
215
201
|
console.log(sample.cpu, sample.memory, sample.disk);
|
|
216
202
|
}
|
|
217
203
|
|
|
218
|
-
for await (const ports of notebook.ports.watch({ signal })) {
|
|
204
|
+
for await (const ports of notebook.runtime.ports.watch({ signal })) {
|
|
219
205
|
console.log(ports);
|
|
220
206
|
}
|
|
221
207
|
|
|
222
|
-
for await (const entry of notebook.logs.follow({ signal })) {
|
|
208
|
+
for await (const entry of notebook.runtime.logs.follow({ signal })) {
|
|
223
209
|
console.log(entry.timestamp, entry.source, entry.message);
|
|
224
210
|
}
|
|
225
211
|
```
|
|
@@ -227,13 +213,15 @@ for await (const entry of notebook.logs.follow({ signal })) {
|
|
|
227
213
|
### Composer
|
|
228
214
|
|
|
229
215
|
```ts
|
|
230
|
-
const install = notebook.composer.install
|
|
216
|
+
const install = notebook.composer.run('install');
|
|
231
217
|
for await (const chunk of install.output) {
|
|
232
218
|
console.log(chunk.source, new TextDecoder().decode(chunk.data));
|
|
233
219
|
}
|
|
234
|
-
|
|
220
|
+
const installResult = await install.wait();
|
|
221
|
+
if (installResult.exitCode !== 0) throw new Error(installResult.stderr || installResult.output);
|
|
235
222
|
|
|
236
|
-
|
|
223
|
+
const requireResult = await notebook.composer.run('require', { packages: ['monolog/monolog'] }).wait();
|
|
224
|
+
if (requireResult.exitCode !== 0) throw new Error(requireResult.stderr || requireResult.output);
|
|
237
225
|
|
|
238
226
|
const installed = await notebook.composer.packages();
|
|
239
227
|
console.log(installed.map((pkg) => pkg.name));
|
|
@@ -338,7 +326,7 @@ const disposeConnect = notebook.onDidConnect(() => {
|
|
|
338
326
|
console.log('connected');
|
|
339
327
|
});
|
|
340
328
|
|
|
341
|
-
const disposeFs = notebook.files.watch(
|
|
329
|
+
const disposeFs = await notebook.files.watch(
|
|
342
330
|
'/app',
|
|
343
331
|
{ recursive: true, excludes: ['vendor/**', 'node_modules/**'] },
|
|
344
332
|
(change) => {
|
|
@@ -354,15 +342,19 @@ disposeFs.dispose();
|
|
|
354
342
|
## Error Handling
|
|
355
343
|
|
|
356
344
|
```ts
|
|
357
|
-
import {
|
|
345
|
+
import { RemoteError, TransportError } from '@phpsandbox/sdk';
|
|
358
346
|
|
|
359
347
|
try {
|
|
360
348
|
await notebook.files.read('/does-not-exist.php');
|
|
361
349
|
} catch (error) {
|
|
362
|
-
if (error
|
|
350
|
+
if (RemoteError.is(error, 'FileNotFound')) {
|
|
363
351
|
console.error('Missing file');
|
|
364
|
-
} else if (error
|
|
365
|
-
console.error(error.
|
|
352
|
+
} else if (RemoteError.isValidation(error)) {
|
|
353
|
+
console.error(error.details.errors);
|
|
354
|
+
} else if (error instanceof RemoteError) {
|
|
355
|
+
console.error(error.source, error.status, error.code, error.message);
|
|
356
|
+
} else if (error instanceof TransportError) {
|
|
357
|
+
console.error(error.code, error.cause);
|
|
366
358
|
} else {
|
|
367
359
|
throw error;
|
|
368
360
|
}
|
|
@@ -371,13 +363,13 @@ try {
|
|
|
371
363
|
|
|
372
364
|
## Browser/CDN Usage
|
|
373
365
|
|
|
374
|
-
See
|
|
366
|
+
See [Browser usage](docs/cdn-usage.md) for ESM and script-tag examples.
|
|
375
367
|
|
|
376
368
|
## More Docs
|
|
377
369
|
|
|
378
|
-
- Getting started walkthrough:
|
|
379
|
-
- API overview:
|
|
380
|
-
- Examples:
|
|
370
|
+
- Getting started walkthrough: [Getting started](docs/getting-started.md)
|
|
371
|
+
- API overview: [API overview](docs/api-summary.md)
|
|
372
|
+
- Examples: [Examples](examples/README.md)
|
|
381
373
|
|
|
382
374
|
## Support
|
|
383
375
|
|
package/dist/beacon/index.d.ts
CHANGED
|
@@ -1,9 +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';
|
|
5
4
|
export * from './types.js';
|
|
6
|
-
export { Navigator } from './navigator.js';
|
|
7
5
|
/**
|
|
8
6
|
* BeaconError for beacon-specific errors
|
|
9
7
|
*/
|
|
@@ -163,11 +161,7 @@ export declare class Beacon implements BeaconActions {
|
|
|
163
161
|
*/
|
|
164
162
|
dispose(): void;
|
|
165
163
|
}
|
|
166
|
-
|
|
167
|
-
* Factory function to create a beacon instance for an iframe
|
|
168
|
-
*/
|
|
169
|
-
export declare function createBeacon(iframe: HTMLIFrameElement, options?: BeaconOptions): Beacon;
|
|
170
|
-
export declare function connectBeacon(notebook: NotebookInstance, iframe: HTMLIFrameElement, options?: BeaconOptions): Promise<Beacon>;
|
|
164
|
+
export declare function connectBeacon(iframe: HTMLIFrameElement, options?: BeaconOptions): Promise<Beacon>;
|
|
171
165
|
/**
|
|
172
166
|
* Check if the current environment supports the Beacon SDK
|
|
173
167
|
*/
|
package/dist/beacon/index.js
CHANGED
|
@@ -3,7 +3,6 @@ import { timeout } from '../utils/promise.js';
|
|
|
3
3
|
import { retry } from '../utils/retry.js';
|
|
4
4
|
import { Navigator } from './navigator.js';
|
|
5
5
|
export * from './types.js';
|
|
6
|
-
export { Navigator } from './navigator.js';
|
|
7
6
|
/**
|
|
8
7
|
* Browser environment check
|
|
9
8
|
*/
|
|
@@ -89,6 +88,9 @@ export class Beacon {
|
|
|
89
88
|
if (event.source !== this.iframe.contentWindow) {
|
|
90
89
|
return;
|
|
91
90
|
}
|
|
91
|
+
if (this.options.targetOrigin !== '*' && event.origin !== this.options.targetOrigin) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
92
94
|
const message = event.data;
|
|
93
95
|
if (!message || typeof message !== 'object' || !message.type) {
|
|
94
96
|
return;
|
|
@@ -151,8 +153,7 @@ export class Beacon {
|
|
|
151
153
|
timestamp: Date.now(),
|
|
152
154
|
id: this.generateId(),
|
|
153
155
|
};
|
|
154
|
-
this.iframe.contentWindow.postMessage(establishMessage,
|
|
155
|
-
[this.messageChannel.port2] // Transfer the port
|
|
156
|
+
this.iframe.contentWindow.postMessage(establishMessage, this.options.targetOrigin, [this.messageChannel.port2] // Transfer the port
|
|
156
157
|
);
|
|
157
158
|
if (this.options.debug) {
|
|
158
159
|
console.log('[Beacon SDK] Channel establishment message sent');
|
|
@@ -524,16 +525,16 @@ export class Beacon {
|
|
|
524
525
|
this.readyPromise = null;
|
|
525
526
|
}
|
|
526
527
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
return
|
|
528
|
+
export async function connectBeacon(iframe, options) {
|
|
529
|
+
const beacon = new Beacon(iframe, options);
|
|
530
|
+
try {
|
|
531
|
+
await beacon.start();
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
beacon.dispose();
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
537
|
+
return beacon;
|
|
537
538
|
}
|
|
538
539
|
/**
|
|
539
540
|
* Check if the current environment supports the Beacon SDK
|
|
@@ -11,7 +11,7 @@ export interface NavigatorActions {
|
|
|
11
11
|
goForward(): Promise<NavigationResult>;
|
|
12
12
|
canGoBack: boolean;
|
|
13
13
|
canGoForward: boolean;
|
|
14
|
-
|
|
14
|
+
reload(): Promise<void>;
|
|
15
15
|
getCurrentUrl(): URL;
|
|
16
16
|
on<K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void): Disposable;
|
|
17
17
|
}
|
|
@@ -46,10 +46,6 @@ export interface HistoryInfoResponse {
|
|
|
46
46
|
canGoBack: boolean;
|
|
47
47
|
canGoForward: boolean;
|
|
48
48
|
}
|
|
49
|
-
export interface Navigator extends NavigatorActions {
|
|
50
|
-
on<K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void): Disposable;
|
|
51
|
-
once<K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void): void;
|
|
52
|
-
}
|
|
53
49
|
/**
|
|
54
50
|
* SDK Navigator implementation with internal history management
|
|
55
51
|
*/
|
|
@@ -61,7 +57,7 @@ export declare class Navigator implements NavigatorActions {
|
|
|
61
57
|
private currentIndex;
|
|
62
58
|
private _canGoBack;
|
|
63
59
|
private _canGoForward;
|
|
64
|
-
constructor(onEvent: <K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void) => Disposable, onceEvent: <K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void) =>
|
|
60
|
+
constructor(onEvent: <K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void) => Disposable, onceEvent: <K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void) => Disposable, beacon: Beacon);
|
|
65
61
|
/**
|
|
66
62
|
* Navigate to a URL using internal history management
|
|
67
63
|
*/
|
|
@@ -97,44 +93,20 @@ export declare class Navigator implements NavigatorActions {
|
|
|
97
93
|
* Get current URL from internal history
|
|
98
94
|
*/
|
|
99
95
|
getCurrentUrl(): URL;
|
|
100
|
-
/**
|
|
101
|
-
* Get the complete history array
|
|
102
|
-
*/
|
|
103
|
-
getHistory(): readonly string[];
|
|
104
|
-
/**
|
|
105
|
-
* Get current history index
|
|
106
|
-
*/
|
|
107
|
-
getCurrentIndex(): number;
|
|
108
|
-
/**
|
|
109
|
-
* Check if can go back synchronously
|
|
110
|
-
*/
|
|
111
|
-
canGoBackSync(): boolean;
|
|
112
|
-
/**
|
|
113
|
-
* Check if can go forward synchronously
|
|
114
|
-
*/
|
|
115
|
-
canGoForwardSync(): boolean;
|
|
116
96
|
/**
|
|
117
97
|
* Emit history change event
|
|
118
98
|
*/
|
|
119
99
|
private emitHistoryChange;
|
|
120
100
|
/**
|
|
121
|
-
*
|
|
122
|
-
*/
|
|
123
|
-
pushState(url: string): Promise<void>;
|
|
124
|
-
/**
|
|
125
|
-
* Replace current state in internal history (legacy method for compatibility)
|
|
126
|
-
*/
|
|
127
|
-
replaceState(url: string): Promise<void>;
|
|
128
|
-
/**
|
|
129
|
-
* Get the current history length
|
|
101
|
+
* Get comprehensive history information
|
|
130
102
|
*/
|
|
131
|
-
|
|
103
|
+
getHistoryInfo(): Promise<HistoryInfoResponse>;
|
|
132
104
|
/**
|
|
133
|
-
*
|
|
105
|
+
* Listen for navigator events
|
|
134
106
|
*/
|
|
135
|
-
|
|
107
|
+
on<K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void): Disposable;
|
|
136
108
|
/**
|
|
137
|
-
*
|
|
109
|
+
* Listen for navigator events (once)
|
|
138
110
|
*/
|
|
139
|
-
|
|
111
|
+
once<K extends keyof NavigatorEvents>(event: K, handler: (payload: NavigatorEvents[K]) => void): Disposable;
|
|
140
112
|
}
|
package/dist/beacon/navigator.js
CHANGED
|
@@ -142,30 +142,6 @@ export class Navigator {
|
|
|
142
142
|
}
|
|
143
143
|
return new URL('about:blank');
|
|
144
144
|
}
|
|
145
|
-
/**
|
|
146
|
-
* Get the complete history array
|
|
147
|
-
*/
|
|
148
|
-
getHistory() {
|
|
149
|
-
return [...this.urlHistory];
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Get current history index
|
|
153
|
-
*/
|
|
154
|
-
getCurrentIndex() {
|
|
155
|
-
return this.currentIndex;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Check if can go back synchronously
|
|
159
|
-
*/
|
|
160
|
-
canGoBackSync() {
|
|
161
|
-
return this.currentIndex > 0;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Check if can go forward synchronously
|
|
165
|
-
*/
|
|
166
|
-
canGoForwardSync() {
|
|
167
|
-
return this.currentIndex < this.urlHistory.length - 1;
|
|
168
|
-
}
|
|
169
145
|
/**
|
|
170
146
|
* Emit history change event
|
|
171
147
|
*/
|
|
@@ -181,43 +157,6 @@ export class Navigator {
|
|
|
181
157
|
});
|
|
182
158
|
}
|
|
183
159
|
}
|
|
184
|
-
/**
|
|
185
|
-
* Push a new state to internal history (legacy method for compatibility)
|
|
186
|
-
*/
|
|
187
|
-
async pushState(url) {
|
|
188
|
-
// For compatibility, treat this as a navigation
|
|
189
|
-
this.visit(url);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Replace current state in internal history (legacy method for compatibility)
|
|
193
|
-
*/
|
|
194
|
-
async replaceState(url) {
|
|
195
|
-
if (this.currentIndex >= 0 && this.currentIndex < this.urlHistory.length) {
|
|
196
|
-
// Replace the current URL in history
|
|
197
|
-
this.urlHistory[this.currentIndex] = url;
|
|
198
|
-
if (!this.beacon) {
|
|
199
|
-
throw new Error('Beacon reference not set');
|
|
200
|
-
}
|
|
201
|
-
this.beacon.navigate(url);
|
|
202
|
-
this.emitHistoryChange(url, 'replace');
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
// If no current history, treat as push
|
|
206
|
-
this.visit(url);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Get the current history length
|
|
211
|
-
*/
|
|
212
|
-
async getHistoryLength() {
|
|
213
|
-
return this.urlHistory.length;
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Get the current history state (always null since we don't store state)
|
|
217
|
-
*/
|
|
218
|
-
async getHistoryState() {
|
|
219
|
-
return null;
|
|
220
|
-
}
|
|
221
160
|
/**
|
|
222
161
|
* Get comprehensive history information
|
|
223
162
|
*/
|
|
@@ -240,6 +179,6 @@ export class Navigator {
|
|
|
240
179
|
* Listen for navigator events (once)
|
|
241
180
|
*/
|
|
242
181
|
once(event, handler) {
|
|
243
|
-
this.onceEvent(event, handler);
|
|
182
|
+
return this.onceEvent(event, handler);
|
|
244
183
|
}
|
|
245
184
|
}
|