@plurnk/plurnk-schemes-http 1.3.11 → 1.4.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/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export { default as Ws } from "./Ws.ts";
4
4
  export { default as Browser } from "./Browser.ts";
5
5
  export type { ChromiumEngine, ChromiumFactory, RenderResult } from "./Browser.ts";
6
6
  export { default as WebFetcher } from "./WebFetcher.ts";
7
- export type { WebFetchResult } from "./WebFetcher.ts";
7
+ export { PROJECTION_ID_HEADER, WebMaterializationError } from "./WebFetcher.ts";
8
+ export type { WebFetchResult, WebMaterializedResult } from "./WebFetcher.ts";
8
9
  export { default as Guard, GuardBlockedError } from "./Guard.ts";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAK5C,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AAIxC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGlF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAG5C,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGlF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAChF,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,16 +1,12 @@
1
- // Public API barrel for @plurnk/plurnk-schemes-http.
2
- // The default export is the scheme class plurnk-service registers at boot
3
- // (plugin discovery scans node_modules/@plurnk/* for `plurnk.kind === "scheme"`).
1
+ // Public package surface. package.json owns plugin registration {§http-manifest}.
4
2
  export { default } from "./Http.js";
5
3
  export { default as Http } from "./Http.js";
6
- // The WebSocket scheme (#468/#473) — this package's second first-class scheme,
7
- // registered `wss` via package.json plurnk.schemes ({ export: "Ws" }); the `ws`
8
- // prefix rides it (core's schemeNameOf, mirroring https → http).
4
+ // The registered WebSocket handler {§ws}.
9
5
  export { default as Ws } from "./Ws.js";
10
- // Standalone render foundation — exported so a future plurnk browser-
11
- // troubleshooting MCP package can sit on the same warm-Chromium pool.
6
+ // Standalone render foundation {§render-lifecycle}.
12
7
  export { default as Browser } from "./Browser.js";
13
- // The guarded prefetch acquisition seam core's entrySink calls (#454).
8
+ // Automatic entry-acquisition primitive {§prefetch} and its URL check.
14
9
  export { default as WebFetcher } from "./WebFetcher.js";
10
+ export { PROJECTION_ID_HEADER, WebMaterializationError } from "./WebFetcher.js";
15
11
  export { default as Guard, GuardBlockedError } from "./Guard.js";
16
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,0EAA0E;AAC1E,kFAAkF;AAClF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C,+EAA+E;AAC/E,gFAAgF;AAChF,iEAAiE;AACjE,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AAExC,sEAAsE;AACtE,sEAAsE;AACtE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAGlD,uEAAuE;AACvE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C,0CAA0C;AAC1C,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AAExC,oDAAoD;AACpD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAGlD,uEAAuE;AACvE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAEhF,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
package/docs/http.md CHANGED
@@ -1,60 +1,102 @@
1
1
  # http(s)://
2
2
 
3
- Fetch a URL. HTML is rendered (headless browser, post-JS) and returned as
4
- **markdown by default** (main content; nav/ads/chrome stripped). Non-HTML
5
- returns its readable content under the response `Content-Type`. Every request
6
- streams its response: status `102` now, then an ordinary fragmentless READ
7
- returns the sanitized body. Auxiliary transport/archive channels are never
8
- presented by default.
9
-
10
- Re-reading a URL without `<scope>` **revalidates** it: the prior fetch's validators (`ETag`/
11
- `Last-Modified`) go out on the next READ, and if the page is unchanged the
12
- stored copy is served without re-rendering — always fresh, but cheap when
13
- nothing changed. Within the operator's freshness window a re-read serves the
14
- stored copy directly, skipping even that check. You just READ again; there's
15
- no cache flag to manage.
16
-
17
- A scoped READ (`READ(url)<start,end>`) observes the already-materialized
18
- readable response without refetching it. If the URL has not been materialized,
19
- READ it once without a scope first.
20
-
21
- The HTTP method is the **op**:
22
-
23
- - `READ(http(s)://…)` — GET.
24
- - `SEND[200](http(s)://…):body:` — POST the body.
25
- - `EDIT(http(s)://…):body:` — PUT the body (replaces the whole resource; no `<L>`).
26
- - `KILL(http(s)://…)` — DELETE the resource.
27
-
28
- The ordinary URL is the model-facing markdown for HTML, or readable response
29
- content for other textual types. Diagnostic channels require explicit access:
30
-
31
- - `#html` — faithful rendered DOM for HTML (`text/html`)
32
- - `#header` — response status line + headers (`text/plain`)
33
-
34
- Request headers ride **inside the target** as trailing `{Key: value}` blocks —
35
- one header per block, so a value may contain commas/colons:
36
-
37
- ```
38
- READ(https://api.example.com/v1/me{Authorization: Bearer TOKEN}{Accept: application/json})
39
- EDIT(https://api.example.com/v1/thing/42{Authorization: Bearer TOKEN}{Content-Type: application/json}):{"done":true}:
3
+ Use a web URL as an addressable entry. An unscoped READ performs a GET
4
+ or reuses a fresh stored GET representation, then streams the selected response
5
+ channel. HTML becomes a readable model-facing body (normally markdown); its
6
+ faithful DOM is retained separately. Auxiliary channels are never presented by
7
+ default.
8
+
9
+ | Operation | Remote action | Effect |
10
+ | --------------------------------- | ------------- | ------------------------------------------------------------------------------ |
11
+ | Unscoped `READ(http(s)://…)` | GET | Acquire/reuse the response and publish the selected channel |
12
+ | Scoped `READ(http(s)://…)<scope>` | None | Read a range from the selected already-materialized channel; never refetch |
13
+ | `FIND(http(s)://…):matcher` | GET if needed | Prepare an exact URL, then return standard JSON metadata and match coordinates |
14
+ | `SEND[200](http(s)://…):body:` | POST | Submit the body and stream the response |
15
+ | `EDIT(http(s)://…):body:` | PUT | Replace the whole remote resource; do not use a line scope |
16
+ | `KILL(http(s)://…)` | DELETE | Delete the remote resource and stream the response |
17
+
18
+ A path-pattern FIND searches only web entries already materialized in the
19
+ workspace; a pattern cannot discover the remote web. FIND returns navigation
20
+ metadata, not the selected page body. Use READ for content.
21
+
22
+ Caller cancellation of an exact acquisition returns `499 cancelled`. The
23
+ independent byte-probe deadline remains an ordinary unavailable result.
24
+
25
+ | Direct response | `body` | Other channel |
26
+ | ------------------------------------ | ------------------------------------------------------------ | ------------------------------------------ |
27
+ | GET HTML | Readable projection of the rendered page | Faithful rendered DOM in `#html` |
28
+ | GET `text/event-stream` | Event `data` chunks after READ `102` | Initial response in `#header` |
29
+ | Configured textual response | Incremental UTF-8 text under its declared type | Status and headers in `#header` |
30
+ | Binary with a readable projection | Derived Unicode under the projection output type | Origin type and projection ID in `#header` |
31
+ | Binary without a readable projection | Empty marker under its type or `application/octet-stream` | Status and headers in `#header` |
32
+
33
+ Projection presence is structural: a returned projection is accepted even
34
+ when its content is empty. `422 no-readable-projection` means exact acquisition,
35
+ or a direct HTML READ, produced no model-facing body. A direct HTML READ retains
36
+ its faithful `#html` and `#header` evidence; exact FIND preparation creates no entry.
37
+ An internal projection exception instead returns non-retryable
38
+ `500 projection-failed`; a browser failure returns retryable
39
+ `502 render-failed`.
40
+
41
+ A binary response uses the installed mimetype reader when one supplies a
42
+ bounded Unicode projection; raw bytes never enter a durable channel. Without a
43
+ reader, a direct operation returns `415 binary-response-unsupported`. Input
44
+ above the configured byte ceiling returns `413 projection-input-limit`. The
45
+ remote response was received and its metadata remains in `#header`; do not
46
+ retry a POST, PUT, or DELETE solely to retrieve its binary body. Exact FIND
47
+ instead prunes responses that produce no readable projection.
48
+
49
+ `#header` contains the remote HTTP status line and headers. The PLURNK
50
+ operation result describes the streaming lifecycle; `SEND[code]` is never the
51
+ remote HTTP status. An HTTP 4xx/5xx response still streams normally and remains
52
+ visible in `#header`.
53
+
54
+ For SSE, the response and persisted `#header` establish acquisition. READ then
55
+ returns `102` while events continue. Origin close settles the subscription at
56
+ `200`; later cancellation or transfer failure settles it at `499` or `502`
57
+ without rewriting the initial READ.
58
+
59
+ Re-reading without a scope can reuse only a complete GET acquired without
60
+ explicit request metadata whose response had no `Vary` field. Plurnk keeps one
61
+ representation per URL, so any target metadata or `Vary` response bypasses both
62
+ the freshness shortcut and old validators instead of creating a variant store.
63
+ Eligible content is served directly only while both the operator TTL and any
64
+ origin `max-age` or `Expires` lifetime remain live. `no-cache` requires origin
65
+ validation; `no-store` evidence remains in the log but supplies neither content
66
+ nor validators to a later request. Only singular, syntactically valid stored
67
+ validators are sent. A 304 restores the stored channels only when its ETag or
68
+ Last-Modified value identifies the nominated representation; otherwise
69
+ acquisition fails without serving the stored body. A valid 304 updates cache
70
+ and validator metadata while preserving fields that describe the
71
+ already-processed body. Responses to POST, PUT, and DELETE are not reused as
72
+ later GET representations. A projected GET is reused only while the installed
73
+ reader has the same projection identity; changing it forces a full acquisition
74
+ without old validators.
75
+
76
+ A scoped READ never fetches. Its fragment, or `body` by default, selects an
77
+ already-materialized channel before the universal READ contract applies the
78
+ range. If that channel is absent, READ the URL without a scope to acquire the
79
+ response first.
80
+
81
+ Request headers ride inside the target as ordered trailing `{Key: value}`
82
+ blocks, one header per block:
83
+
84
+ ```plurnk
85
+ <<READ(https://api.example.com/v1/me{Authorization: Bearer TOKEN}{Accept: application/json})::READ
86
+ <<EDIT(https://api.example.com/v1/thing/42{Authorization: Bearer TOKEN}{Content-Type: application/json}):{"done":true}:EDIT
40
87
  ```
41
88
 
42
- Percent-encode `)`, `<`, and `}` inside a header value (the path-encoding rule).
43
-
44
- Host handling: a GitHub `…/blob/…` URL is fetched as its `raw.githubusercontent.com`
45
- source (line-navigable, exact) rather than the JS code-viewer page — so
46
- `READ(https://github.com/owner/repo/blob/main/src/x.ts)` returns the file's source.
47
-
48
- Cancel / cache:
49
-
50
- - `SEND[499](http(s)://…)` — cancel an in-flight request (abort the fetch).
51
- - `SEND[410](http(s)://…)` — drop the locally cached copy, forcing the next READ
52
- to full-fetch instead of revalidate. A local cache drop, **not** an HTTP
53
- DELETE — use `KILL` to DELETE the remote resource.
89
+ Percent-encode `)`, `<`, and `}` inside a header value.
90
+ An exact FIND forwards these headers when it must acquire the URL, but the
91
+ result remains intentionally ineligible for later cache reuse.
54
92
 
55
- The `SEND[code]` is loop disposition (`102`/`200`/…), never the HTTP status —
56
- the real `2xx`/`4xx` comes back in `#header`.
93
+ GET acquisition of a GitHub `…/blob/…` URL uses its
94
+ `raw.githubusercontent.com` source. The addressed GitHub URL remains entry
95
+ identity. POST, PUT, and DELETE never use that rewrite.
57
96
 
58
- Status: `102` streaming · `499` cancelled · `502` upstream/render failure.
97
+ | Control | Effect |
98
+ | ------------------------ | --------------------------------------------------------------------- |
99
+ | `SEND[499](http(s)://…)` | Cancel the routed in-flight acquisition |
100
+ | `SEND[410](http(s)://…)` | Delete the local stored response; the next READ must acquire it again |
59
101
 
60
- For a persistent, bidirectional connection, see the `wss://` scheme.
102
+ For a persistent bidirectional connection, use `wss://`.
package/docs/wss.md CHANGED
@@ -1,45 +1,41 @@
1
1
  # wss:// — WebSocket
2
2
 
3
- A full-duplex, persistent connection to a WebSocket origin. Unlike `http://`
4
- (request/response) or SSE (a one-way `http://` event stream), a WebSocket is
5
- **bidirectional and stateful**: you open it once, then send and receive on the
6
- same live connection until it closes.
7
-
8
- ## Ops
9
-
10
- | Op | Effect |
11
- | --- | --- |
12
- | `READ(wss://host/path)` | Open the socket. Inbound frames stream into the `messages` channel as they arrive; the READ holds until the socket closes. |
13
- | `SEND[200](wss://host/path):your message:` | Push a message onto the **already-open** socket. READ it first — a SEND with no open socket is a `409`. |
14
- | `SEND[499](wss://host/path)` | Cancel: closes the open socket. |
15
- | `KILL(wss://host/path)` | Close the open socket. |
16
-
17
- ```
18
- <<READ(wss://echo.websocket.events)::READ
19
- <<SEND[200](wss://echo.websocket.events):hello:SEND
20
- <<KILL(wss://echo.websocket.events)::KILL
21
- ```
22
-
23
- A READ returns `102 Processing` and the socket's inbound frames accumulate in the
24
- `messages` channel across turns — read them as they land, the way you read any
25
- streaming subscription. The connection stays open for concurrent `SEND`s until
26
- you `KILL` it or the origin closes.
27
-
28
- ## Model
29
-
30
- - **One socket per target, per workspace.** The connection a READ opens is keyed by
31
- its path; a later SEND/KILL to the same target acts on that connection.
32
- - **SSRF-guarded.** The target is resolved and checked before connecting — a
33
- `ws://`/`wss://` into loopback, link-local, or RFC-1918/CGNAT space is refused
34
- (`403`), the same guard the fetch path uses.
35
-
36
- ## Day-one limits
37
-
38
- - **Text frames only.** Binary frames stringify loosely; structured binary is a
39
- follow-up (#468).
40
- - **No reconnection.** A dropped socket closes the READ; re-READ to reopen.
41
- - **Default handshake identity.** Custom request headers on the WebSocket
42
- handshake aren't wired yet (the standard `WebSocket` constructor has no header
43
- slot); pending, tracked on #468.
44
-
45
- Runtime: Node ≥22 (global `WebSocket`).
3
+ Use WebSocket for a persistent, bidirectional connection. `wss` is a
4
+ stateful scheme, not an HTTP content type: READ claims a workspace address and
5
+ owns its socket until terminal settlement, while concurrent SEND and KILL
6
+ operations address that owner.
7
+
8
+ | Operation | Effect |
9
+ | ------------------------------------- | ------------------------------------------------------------------------------------------ |
10
+ | `READ(wss://host/path)` | Claim the address, connect, mark `messages` active on `open`, and stream inbound frames |
11
+ | A second `READ` of the same address | Return `409` until the existing owner's terminal cleanup releases the claim |
12
+ | `SEND[200](wss://host/path):message:` | Send only through an open socket; claimed, connecting, or settling owners return `409` |
13
+ | `SEND[499](wss://host/path)` | Cancel the owning READ through its routed subscription handle |
14
+ | `KILL(wss://host/path)` | Close or cancel the claimed owner; an address with no owner is `404` |
15
+
16
+ | Owner state | Meaning | `SEND[200]` |
17
+ | ------------ | ---------------------------------------------------- | ------------------------------------------------ |
18
+ | `claimed` | Address reserved while entry/subscription setup runs | `409`; no second ownership path is created |
19
+ | `connecting` | Native socket exists but has not emitted `open` | `409`; wait for the active stream event |
20
+ | `open` | `open` was observed and the native state is open | Sends the message |
21
+ | `settling` | A terminal transition owns cleanup | `409`; wait for cleanup before another READ |
22
+
23
+ The native `open` event plus durable `messages` activation is the acquisition
24
+ boundary. It emits the ordinary metadata-only stream event and returns the READ
25
+ at `102`; later operations from the same worker or client may then SEND or KILL
26
+ the live owner. A close before acquisition is a direct `502` connection
27
+ failure. After acquisition, close, cancellation, and failure settle the retained
28
+ subscription without rewriting the initial READ.
29
+
30
+ Connection identity includes the workspace, exact `ws`/`wss` protocol, host,
31
+ non-default port, path, and ordered query. A fragment does not change socket
32
+ identity; `messages` is the only current channel.
33
+
34
+ | Current transport boundary | Behavior |
35
+ | -------------------------- | ----------------------------------------------------------------------- |
36
+ | Inbound payload | String event data only; no coercion or binary projection |
37
+ | Inbound order | Native event order; one durable write completes before the next begins |
38
+ | Binary inbound payload | Keep the text prefix, prune the suffix, settle `415`, and close `1003` |
39
+ | Persistence failure | Keep the successful prefix; prune queued and later frames; settle `500` |
40
+ | Reconnection | None; READ again after terminal cleanup |
41
+ | Handshake headers | Target header metadata is not applied |
package/package.json CHANGED
@@ -1,21 +1,25 @@
1
1
  {
2
2
  "name": "@plurnk/plurnk-schemes-http",
3
- "version": "1.3.11",
4
- "description": "http(s):// URI scheme handler for the plurnk agent runtime — fetch + streaming response body.",
3
+ "version": "1.4.0",
4
+ "description": "HTTP(S) request/response and WebSocket scheme handlers for the plurnk agent runtime.",
5
5
  "keywords": [
6
6
  "plurnk",
7
7
  "scheme",
8
8
  "uri",
9
9
  "http",
10
- "https"
10
+ "https",
11
+ "websocket",
12
+ "ws",
13
+ "wss"
11
14
  ],
12
- "homepage": "https://github.com/plurnk/plurnk-schemes-http#readme",
15
+ "homepage": "https://github.com/plurnk/plurnk-service/tree/main/plurnk-schemes-http#readme",
13
16
  "bugs": {
14
- "url": "https://github.com/plurnk/plurnk-schemes-http/issues"
17
+ "url": "https://repo.possumtech.com/plurnk/plurnk-service/issues"
15
18
  },
16
19
  "repository": {
17
20
  "type": "git",
18
- "url": "git+https://github.com/plurnk/plurnk-schemes-http.git"
21
+ "url": "git+https://github.com/plurnk/plurnk-service.git",
22
+ "directory": "plurnk-schemes-http"
19
23
  },
20
24
  "engines": {
21
25
  "node": ">=26"
@@ -49,7 +53,6 @@
49
53
  },
50
54
  "files": [
51
55
  "dist/**/*",
52
- "scripts/**/*",
53
56
  ".env.defaults",
54
57
  "docs/**/*",
55
58
  "README.md",
@@ -60,17 +63,17 @@
60
63
  "test:unit": "node --conditions=plurnk-dev --test --env-file=.env.defaults src/**/*.test.ts",
61
64
  "test:intg": "node --conditions=plurnk-dev --test --env-file=.env.defaults test/integration/**/*.test.ts",
62
65
  "test": "npm run test:lint && npm run test:unit",
66
+ "build:clean": "rm -rf dist",
63
67
  "build:dist": "tsc -p tsconfig.build.json",
64
- "build": "npm run build:dist",
65
- "postinstall": "node scripts/install-browser.mjs",
68
+ "build": "npm run build:clean && npm run build:dist",
66
69
  "prepublishOnly": "npm audit --audit-level=moderate && npm test",
67
70
  "prepack": "npm run build"
68
71
  },
69
72
  "peerDependencies": {
70
- "@plurnk/plurnk-schemes": "^1.3.11"
73
+ "@plurnk/plurnk-schemes": "^1.4.0"
71
74
  },
72
75
  "dependencies": {
73
76
  "eventsource-parser": "^3.1.0",
74
- "playwright": "1.62.0"
77
+ "playwright": "1.62.1"
75
78
  }
76
79
  }
@@ -1,19 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- import { dirname, resolve } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
-
5
- const skipped = /^(1|true|yes)$/i.test(process.env.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD ?? "");
6
- if (skipped) {
7
- console.info("plurnk-schemes-http: browser download skipped by PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD");
8
- process.exit(0);
9
- }
10
-
11
- const playwrightEntry = fileURLToPath(import.meta.resolve("playwright"));
12
- const cli = resolve(dirname(playwrightEntry), "cli.js");
13
- const env = {
14
- ...process.env,
15
- PLAYWRIGHT_BROWSERS_PATH: process.env.PLAYWRIGHT_BROWSERS_PATH ?? "0",
16
- };
17
- const result = spawnSync(process.execPath, [cli, "install", "chromium"], { stdio: "inherit", env });
18
- if (result.error) throw result.error;
19
- process.exit(result.status ?? 1);