@push.rocks/smartbrowser 3.0.0 → 4.0.0
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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/classes.livebrowsercanvasrenderer.d.ts +25 -5
- package/dist_ts_web/classes.livebrowsercanvasrenderer.js +385 -136
- package/dist_ts_web/interfaces.livebrowsercanvas.d.ts +18 -6
- package/package.json +3 -3
- package/readme.hints.md +11 -6
- package/readme.md +19 -7
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/classes.livebrowsercanvasrenderer.ts +483 -149
- package/ts_web/interfaces.livebrowsercanvas.ts +34 -5
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import type { ILiveBrowserFrame, ILiveBrowserFrameAcknowledgement, ILiveBrowserFrameAcknowledgementRequest, ILiveBrowserInsertTextInput, ILiveBrowserKeyInput, ILiveBrowserMouseInput, ILiveBrowserState, ILiveBrowserViewport, ILiveBrowserWheelInput, TLiveBrowserEventListener } from '@push.rocks/smartpuppeteer';
|
|
2
|
+
/**
|
|
3
|
+
* Transport adapter for one renderer. Frame events must use strictly increasing
|
|
4
|
+
* sequence values for each onEvent subscription/renderer run.
|
|
5
|
+
*/
|
|
2
6
|
export interface ILiveBrowserCanvasClient {
|
|
3
7
|
getState(): ILiveBrowserState;
|
|
4
8
|
onEvent(listenerArg: TLiveBrowserEventListener): () => void;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* A fulfilled result, including accepted: false, settles the local attempt.
|
|
11
|
+
* It does not prove that the upstream frame was retired.
|
|
12
|
+
*/
|
|
13
|
+
acknowledgeFrame(requestArg: ILiveBrowserFrameAcknowledgementRequest, optionsArg: ILiveBrowserCanvasOperationOptions): Promise<ILiveBrowserFrameAcknowledgement>;
|
|
14
|
+
setViewport(viewportArg: ILiveBrowserViewport, optionsArg: ILiveBrowserCanvasOperationOptions): Promise<void>;
|
|
15
|
+
dispatchMouse(inputArg: ILiveBrowserMouseInput, optionsArg: ILiveBrowserCanvasOperationOptions): Promise<void>;
|
|
16
|
+
dispatchWheel(inputArg: ILiveBrowserWheelInput, optionsArg: ILiveBrowserCanvasOperationOptions): Promise<void>;
|
|
17
|
+
dispatchKey(inputArg: ILiveBrowserKeyInput, optionsArg: ILiveBrowserCanvasOperationOptions): Promise<void>;
|
|
18
|
+
insertText(inputArg: ILiveBrowserInsertTextInput, optionsArg: ILiveBrowserCanvasOperationOptions): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export interface ILiveBrowserCanvasOperationOptions {
|
|
21
|
+
/** Adapters must propagate this signal and reject promptly when it aborts. */
|
|
22
|
+
signal: AbortSignal;
|
|
11
23
|
}
|
|
12
24
|
export type TLiveBrowserCanvasErrorCode = 'frame_acknowledgement_failed' | 'frame_render_failed' | 'input_dispatch_failed' | 'input_queue_capacity_exceeded' | 'remote_browser_error' | 'renderer_callback_failed' | 'renderer_cleanup_failed' | 'viewport_update_failed';
|
|
13
25
|
export interface ILiveBrowserCanvasError {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartbrowser",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "A simplified Puppeteer wrapper for easy automation and testing tasks.",
|
|
5
5
|
"main": "dist_ts/index.js",
|
|
6
6
|
"typings": "dist_ts/index.d.ts",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@push.rocks/smartdelay": "^3.1.0",
|
|
33
33
|
"@push.rocks/smartpdf": "^5.0.1",
|
|
34
|
-
"@push.rocks/smartpuppeteer": "^2.
|
|
34
|
+
"@push.rocks/smartpuppeteer": "^2.4.0",
|
|
35
35
|
"@push.rocks/smartunique": "^3.0.10"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@git.zone/tsbuild": "^4.4.2",
|
|
39
39
|
"@git.zone/tsrun": "^2.0.6",
|
|
40
40
|
"@git.zone/tstest": "^4.0.0",
|
|
41
|
-
"@types/node": "^26.
|
|
41
|
+
"@types/node": "^26.2.0"
|
|
42
42
|
},
|
|
43
43
|
"private": false,
|
|
44
44
|
"files": [
|
package/readme.hints.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# SmartBrowser Hints
|
|
2
2
|
|
|
3
|
-
## Dependencies (as of 2026-08-
|
|
4
|
-
- `@push.rocks/smartpdf` v5.x uses SmartPuppeteer 2
|
|
5
|
-
- `@push.rocks/smartpuppeteer` v2.
|
|
3
|
+
## Dependencies (as of 2026-08-15)
|
|
4
|
+
- `@push.rocks/smartpdf` v5.x uses SmartPuppeteer 2/Puppeteer 25 browser types. `SmartPdf` remains lazy and starts only for PDF methods.
|
|
5
|
+
- `@push.rocks/smartpuppeteer` v2.4 owns `LiveBrowserSession`, the canonical transport-neutral live browser contracts, and bounded CDP frame acknowledgement flow.
|
|
6
6
|
- Tests import `@git.zone/tstest/tapbundle`; browser tests use the `.chromium.ts` suffix.
|
|
7
7
|
- The Node.js entry requires Node.js 22.12 or newer. This repository uses pnpm 11.20 for development and release tooling.
|
|
8
8
|
- Puppeteer `page.screenshot({ encoding: 'binary' })` returns `Uint8Array`, not `Buffer` - wrap with `Buffer.from()`
|
|
@@ -16,10 +16,15 @@
|
|
|
16
16
|
- The client facade is transport-neutral. Authentication, authorization, binary wire encoding, session ownership, and egress policy belong to the consuming adapter.
|
|
17
17
|
- Input always carries the identity of the actually displayed frame, never merely the newest state event.
|
|
18
18
|
- Cached state may lag a new frame generation. A state identity ahead of the displayed frame invalidates it; same-identity metadata updates do not.
|
|
19
|
-
- One frame may decode while only the newest subsequent frame waits.
|
|
20
|
-
-
|
|
19
|
+
- One frame may decode while only the newest subsequent frame waits. Active-run frames must pass full static validation and then have a sequence strictly above the per-run high-water value. Duplicate and out-of-order frames suspend without acknowledgement; resume resets the high-water value.
|
|
20
|
+
- The renderer makes at most one acknowledgement request for each valid drawn, stale, superseded, or decode-failed frame while its run remains active. Interrupted and invalid-protocol frames do not start acknowledgement work. An acknowledgement that throws, rejects, or times out suspends the run; `{ accepted: false }` settles the local attempt and does not prove upstream retirement.
|
|
21
|
+
- Every asynchronous client method receives `ILiveBrowserCanvasOperationOptions` with a renderer-owned `AbortSignal`. Operation deadline, run suspension, and stop all abort the signal; adapters must propagate it through the underlying transport.
|
|
22
|
+
- Renderer starts, suspensions, resumes, and stops are serialized by run epoch. Suspension aborts owned work and drops state, frames, queued input, pressed state, and old-generation recovery. Resume creates a fresh epoch and requires newly read state plus a newly displayed frame before input.
|
|
23
|
+
- Native `createImageBitmap()` jobs are tracked outside per-run cleanup. A new start or resume waits for every prior raw decode to settle, and late bitmaps are closed after timeout or interruption. Start or resume can remain pending indefinitely if the browser never settles native decode work.
|
|
24
|
+
- Acknowledgement failures, input-release failures, capacity exhaustion, and client/decode timeouts suspend only the current run. Malformed, oversized, or inconsistent frame protocol and deterministic decode-integrity failures are also terminal to that run. Recovery is explicit through `resume()`; none of these paths retries automatically.
|
|
25
|
+
- Internal renderer ceilings are 16 pending acknowledgements; 12,288 per frame dimension and 8,294,400 frame pixels; 34,226,176 encoded bytes; and a 4,096 x 4,096 viewport, device scale factor 3, and 8,294,400 physical pixels.
|
|
21
26
|
- Repeated blur, visibility, and pointer-loss resets coalesce into one bounded reset operation.
|
|
22
|
-
-
|
|
27
|
+
- During an active run, pressed input is retained until release succeeds, with one retry for transient release failures. Input remains blocked while a release is unresolved. Suspension discards pressed state without dispatching releases into a later run.
|
|
23
28
|
- Resize uses a caller-supplied stable CSS element. Requests are latest-only and serialized; input is released before resizing and remains blocked until a frame meeting the target revision fence is drawn.
|
|
24
29
|
- Intrinsic canvas dimensions come from encoded frame dimensions. Pointer coordinates map to the frame's logical CSS viewport.
|
|
25
30
|
- Pointer and wheel listeners remain on the canvas. Keyboard and composition listeners use `focusTarget`, which defaults to the canvas. Call `insertText()` for text committed by an external IME or dedicated input control.
|
package/readme.md
CHANGED
|
@@ -15,7 +15,7 @@ Install the package with pnpm:
|
|
|
15
15
|
pnpm add @push.rocks/smartbrowser
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
The Node.js entry requires Node.js 22.12 or newer and a Chromium-compatible browser. It uses SmartPuppeteer 2.
|
|
18
|
+
The Node.js entry requires Node.js 22.12 or newer and a Chromium-compatible browser. It uses SmartPuppeteer 2.4, Puppeteer 25, and SmartPDF 5. SmartPuppeteer detects common local, CI, and container environments and configures Chromium accordingly.
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
@@ -106,7 +106,7 @@ const browser = await smartpuppeteer.getEnvAwareBrowserInstance();
|
|
|
106
106
|
|
|
107
107
|
Import the browser-only renderer from `@push.rocks/smartbrowser/web`. The Node.js root entry is intentionally separate and must not be imported into a frontend bundle.
|
|
108
108
|
|
|
109
|
-
The renderer receives a caller-provided `ILiveBrowserCanvasClient`. An application adapter implements that interface using its authenticated transport and keeps the latest `ILiveBrowserState` available through `getState()`. SmartBrowser does not prescribe TypedSocket, WebSocket framing, base64 conversion, authentication, authorization, or session ownership.
|
|
109
|
+
The renderer receives a caller-provided `ILiveBrowserCanvasClient`. An application adapter implements that interface using its authenticated transport and keeps the latest `ILiveBrowserState` available through `getState()`. The adapter must emit frame events with strictly increasing `frame.sequence` values for each `onEvent()` subscription/renderer run. SmartBrowser does not prescribe TypedSocket, WebSocket framing, base64 conversion, authentication, authorization, or session ownership.
|
|
110
110
|
|
|
111
111
|
```typescript
|
|
112
112
|
import {
|
|
@@ -128,7 +128,7 @@ export async function mountLiveBrowser(client: ILiveBrowserCanvasClient) {
|
|
|
128
128
|
|
|
129
129
|
await renderer.start();
|
|
130
130
|
return async () => {
|
|
131
|
-
// Stop the renderer before closing its transport so
|
|
131
|
+
// Stop the renderer before closing its transport so cancellation reaches the adapter.
|
|
132
132
|
await renderer.stop();
|
|
133
133
|
};
|
|
134
134
|
}
|
|
@@ -149,7 +149,19 @@ A minimal host keeps CSS sizing independent from the canvas's encoded backing di
|
|
|
149
149
|
- Viewport synchronization: `setViewport()`
|
|
150
150
|
- Input: `dispatchMouse()`, `dispatchWheel()`, `dispatchKey()`, and `insertText()`
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
Every asynchronous client method receives a required second `ILiveBrowserCanvasOperationOptions` argument containing `signal: AbortSignal`. Adapters must pass that signal through to their transport operation and reject promptly when it aborts. The renderer aborts it at the operation deadline and when the current run is suspended or stopped. There is no compatibility path for adapters that omit cancellation.
|
|
153
|
+
|
|
154
|
+
The renderer keeps at most one frame decoding and one newest frame queued. For an active run it validates the complete static frame protocol before requiring `frame.sequence` to be strictly greater than that run's high-water sequence. Duplicate or out-of-order frames are terminal `frame_render_failed` protocol errors and are not acknowledged. A resumed run creates a new subscription and resets the high-water sequence by design.
|
|
155
|
+
|
|
156
|
+
The renderer makes one acknowledgement attempt after a valid frame is drawn, deliberately dropped, found stale, superseded, or fails decoding while its run remains active. SmartPuppeteer may fulfill an acknowledgement with `{ accepted: false }` for stale, retired, duplicate, or identity-mismatched frames. That result settles the renderer's local attempt without suspending or retrying, and it does not prove upstream retirement. Only an acknowledgement operation that throws, rejects, or times out suspends the run; reaching acknowledgement capacity does the same. Input identity always comes from the frame actually displayed, so tab, generation, and viewport changes block stale clicks and keystrokes. Encoded `frame.width` and `frame.height` set the canvas backing bitmap, while pointer coordinates map through the displayed canvas rectangle into the frame's logical CSS viewport.
|
|
157
|
+
|
|
158
|
+
Call `suspend()` when the adapter observes a transport interruption, then call `resume()` after the adapter has established a fresh transport. Suspension aborts active work, removes listeners, drops queued input and pressed-input recovery, and clears state and the displayed frame. `resume()` creates a new renderer run generation, re-subscribes to events, reads state again, and keeps input blocked until a new matching frame is displayed. Old input and release transitions are never replayed into the new generation. Operation timeouts request this same suspended lifecycle, so one transient acknowledgement timeout does not permanently poison the renderer instance.
|
|
159
|
+
|
|
160
|
+
Malformed frame identities, metadata, viewport values, formats, MIME pairings, dimensions, pixel areas, byte lengths, and deterministic image decode or dimension-integrity failures are terminal to the current run. Decoded dimensions are checked before supersession and currentness, so a mismatched decoded bitmap remains terminal even when a newer frame arrived during decoding. These failures are reported as `frame_render_failed` and require an explicit `resume()`; the renderer does not retry them automatically. The renderer only schedules rendering, acknowledgements, viewport synchronization, and direct input. Navigation scheduling remains the responsibility of the server runtime and application adapter.
|
|
161
|
+
|
|
162
|
+
The renderer's fixed internal protocol ceilings are 16 pending frame acknowledgement operations; frame dimensions of at most 12,288 on either axis and 8,294,400 pixels; encoded frame data of at most 34,226,176 bytes; and viewports of at most 4,096 x 4,096 CSS pixels, device scale factor 3, and 8,294,400 physical pixels (`width * height * deviceScaleFactor^2`).
|
|
163
|
+
|
|
164
|
+
Browser-native `createImageBitmap()` work is not abortable. After a wrapper timeout or run interruption, the renderer closes a bitmap that resolves late and waits for all prior raw decode jobs to settle before `start()` or `resume()` starts another run. Consequently, `start()` or `resume()` can remain pending indefinitely if the browser platform never settles a prior `createImageBitmap()` call.
|
|
153
165
|
|
|
154
166
|
Pointer and wheel input are captured from the canvas. Keyboard and best-effort `compositionend` input are captured from `focusTarget`, which defaults to the canvas and receives focus on pointer down. The renderer temporarily makes an unfocusable focus target focusable and restores its prior `tabindex` on stop. Applications with a dedicated text or IME control can call `renderer.insertText(text)` explicitly.
|
|
155
167
|
|
|
@@ -161,12 +173,12 @@ When `resizeTarget` is supplied, resize updates are deduplicated, serialized, an
|
|
|
161
173
|
- `focusTarget`: optional keyboard and composition event target; defaults to `canvas`.
|
|
162
174
|
- `resizeTarget`: optional stable CSS-sized element observed for remote viewport updates.
|
|
163
175
|
- `getDeviceScaleFactor`: optional scale provider; defaults to `window.devicePixelRatio` and is useful when the application controls remote scaling explicitly.
|
|
164
|
-
- `operationTimeoutMs`:
|
|
165
|
-
- `frameDecodeTimeoutMs`: image decode
|
|
176
|
+
- `operationTimeoutMs`: deadline for client acknowledgements, viewport updates, and input operations; defaults to 10 seconds. Reaching it aborts the operation signal and suspends the run.
|
|
177
|
+
- `frameDecodeTimeoutMs`: image decode wrapper deadline; defaults to `operationTimeoutMs`. Reaching it suspends the run and closes the decoded bitmap if it completes late, but cannot force the browser's native decode job to settle.
|
|
166
178
|
- `onError`: receives typed `ILiveBrowserCanvasError` values without interrupting renderer cleanup.
|
|
167
179
|
- `onFrameRendered`: called after a current frame has been drawn.
|
|
168
180
|
|
|
169
|
-
The renderer exposes `start()`, `stop()`, `insertText()`, `syncViewport()`, and the `isRunning`
|
|
181
|
+
The renderer exposes `start()`, `suspend()`, `resume()`, `stop()`, `insertText()`, `syncViewport()`, and the `isRunning` and `isSuspended` getters. `start()` begins a stopped renderer, while `resume()` is required for a suspended renderer. `syncViewport()` requests a fresh measurement of the configured `resizeTarget`; it is a no-op when no target is configured or the renderer is not running. An explicitly stopped renderer can be started again. The `/web` entry also exports `ILiveBrowserCanvasClient`, `ILiveBrowserCanvasOperationOptions`, `ILiveBrowserCanvasRendererOptions`, `ILiveBrowserCanvasError`, `TLiveBrowserCanvasErrorCode`, and the canonical SmartPuppeteer live-browser contract types.
|
|
170
182
|
|
|
171
183
|
`LiveBrowserCanvasRenderer` is not a security boundary. The application adapter must authenticate viewers, authorize control, restrict navigation, enforce browser-session ownership, and apply network/egress policy before forwarding commands. The renderer displays webpage viewport pixels only. It does not provide native Chrome UI, audio, extensions, file transfer, clipboard, camera, microphone, or touch emulation.
|
|
172
184
|
|
package/ts/00_commitinfo_data.ts
CHANGED