Skip to content

Commit 12e8e76

Browse files
authored
Merge pull request #3 from lightpanda-io/fix/browser-package
Fix/browser package
2 parents 5635d9f + ab98bc2 commit 12e8e76

File tree

9 files changed

+203
-32
lines changed

9 files changed

+203
-32
lines changed

packages/browser/README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,13 @@ See [benchmark details](https://github.com/lightpanda-io/demo)._
5151

5252
## Getting Started
5353

54+
### Configuration
55+
_Environment variables_
56+
- `LIGHTPANDA_EXECUTABLE_PATH` can be specified if you want to use your own version and avoid the binary from being installed on postinstall. The default folder is `~/.cache/lightpanda-node`
57+
58+
5459
### Install
55-
_On installation, the binary corresponding to your platform will be automatically downloaded_
60+
_When installing the package, the binary corresponding to your platform will be automatically downloaded. If your OS is not supported, download will fail_
5661

5762
```bash
5863
yarn add @lightpanda/browser
@@ -72,7 +77,7 @@ pnpm add @lightpanda/browser
7277

7378
At some point in time, you might want to upgrade Lightpanda browser to a more recent version. To do so, you can run the following command:
7479
```bash
75-
npx @lightpanda/browser
80+
npx @lightpanda/browser upgrade
7681
```
7782

7883
<!-- USAGE EXAMPLES -->

packages/browser/cli/install.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

packages/browser/cli/main.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env node
2+
3+
import yargs from 'yargs'
4+
import { hideBin } from 'yargs/helpers'
5+
6+
import { download } from '../src/download'
7+
8+
yargs(hideBin(process.argv))
9+
.command(
10+
'upgrade',
11+
'Upgrade the browser to the latest nightly version',
12+
() => {},
13+
_ => {
14+
download()
15+
},
16+
)
17+
.command(
18+
'$0',
19+
'Default',
20+
() => {},
21+
_ => {
22+
console.info('ℹ️ Please enter a command')
23+
},
24+
)
25+
.option('verbose', {
26+
alias: 'v',
27+
type: 'boolean',
28+
description: 'Run with verbose logging',
29+
})
30+
.parse()

packages/browser/package.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@
44
"description": "Lightpanda for Node.js",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",
7-
"types": "./dist/types/index.d.ts",
7+
"types": "./dist/index.d.ts",
88
"type": "module",
99
"scripts": {
1010
"dev": "tsup index.ts --target node22 --format cjs,esm --dts --watch",
1111
"build:index": "tsup index.ts --target node22 --format cjs,esm --minify terser",
12-
"build:decl": "yarn dlx --package=typescript tsc --emitDeclarationOnly --declaration --declarationDir dist/types",
13-
"build:cli": "tsup cli/install.ts --target node22 --format cjs,esm --minify terser -d dist/cli",
12+
"build:decl": "yarn dlx --package=typescript tsc --emitDeclarationOnly --declaration",
13+
"build:cli": "tsup cli/main.ts --target node22 --format cjs,esm --minify terser -d dist/cli",
1414
"build:postinstall": "tsup scripts/postinstall.ts --target node22 --format cjs,esm --minify terser -d dist/scripts",
1515
"build": "yarn build:index && yarn build:decl && yarn build:cli && yarn build:postinstall",
1616
"postinstall": "node dist/scripts/postinstall.js || true",
1717
"lint": "biome ci . --diagnostic-level=error",
1818
"typecheck": "yarn dlx --package=typescript tsc --noEmit"
1919
},
2020
"bin": {
21-
"lightpanda": "./dist/cli/install.js"
21+
"lightpanda": "./dist/cli/main.js"
2222
},
2323
"repository": {
2424
"type": "git",
@@ -38,8 +38,12 @@
3838
"devDependencies": {
3939
"@biomejs/biome": "^1.9.4",
4040
"@types/node": "22.15.32",
41+
"@types/yargs": "^17.0.33",
4142
"terser": "^5.43.1",
4243
"tsup": "^8.5.0",
4344
"typescript": "^5.8.3"
45+
},
46+
"dependencies": {
47+
"yargs": "^18.0.0"
4448
}
4549
}

packages/browser/src/download.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import { constants, chmodSync, createWriteStream } from 'node:fs'
1+
import { constants, chmodSync, createWriteStream, existsSync, mkdirSync } from 'node:fs'
22
import https from 'node:https'
33
import { arch, exit, platform } from 'node:process'
4-
5-
const FOLDER = 'dist'
6-
const BINARY_NAME = 'lightpanda'
7-
const BINARY_PATH = `${FOLDER}/${BINARY_NAME}`
4+
import { DEFAULT_CACHE_FOLDER, DEFAULT_EXECUTABLE_PATH, USER_EXECUTABLE_PATH } from './utils'
85

96
const PLATFORMS = {
107
darwin: {
@@ -21,11 +18,15 @@ const PLATFORMS = {
2118
* Download Lightpanda's binary
2219
* @returns {Promise<void>}
2320
*/
24-
export const download = async (binaryPath: string = BINARY_PATH): Promise<void> => {
25-
const path = PLATFORMS?.[platform]?.[arch]
21+
export const download = async (): Promise<void> => {
22+
const platformPath = PLATFORMS?.[platform]?.[arch]
23+
24+
if (!existsSync(DEFAULT_CACHE_FOLDER)) {
25+
mkdirSync(DEFAULT_CACHE_FOLDER, { recursive: true })
26+
}
2627

2728
const get = (url: string, resolve: (value?: unknown) => void, reject: (reason: any) => void) => {
28-
const file = createWriteStream(binaryPath)
29+
const file = createWriteStream(DEFAULT_EXECUTABLE_PATH)
2930

3031
https.get(url, res => {
3132
if (
@@ -50,20 +51,25 @@ export const download = async (binaryPath: string = BINARY_PATH): Promise<void>
5051
return new Promise((resolve, reject) => get(url, resolve, reject))
5152
}
5253

53-
if (path) {
54+
if (platformPath) {
55+
if (USER_EXECUTABLE_PATH) {
56+
console.info('$LIGHTPANDA_EXECUTABLE_PATH found, skipping binary download…')
57+
exit(0)
58+
}
59+
5460
try {
5561
console.info('⏳ Downloading latest version of Lightpanda browser…')
5662

5763
await downloadBinary(
58-
`https://github.com/lightpanda-io/browser/releases/download/nightly/lightpanda-${path}`,
64+
`https://github.com/lightpanda-io/browser/releases/download/nightly/lightpanda-${platformPath}`,
5965
)
60-
chmodSync(binaryPath, constants.S_IRWXU)
66+
chmodSync(DEFAULT_EXECUTABLE_PATH, constants.S_IRWXU)
6167

62-
console.info('✅ Download finished!')
68+
console.info('✅ Done!')
6369
exit(0)
6470
} catch (e) {
6571
console.log('error', e)
66-
console.warn(`Lightpanda's failed to download the binary file "${path}".`)
72+
console.warn(`Lightpanda's failed to download the binary file "${platformPath}".`)
6773
exit(1)
6874
}
6975
} else {

packages/browser/src/fetch.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { execSync } from 'node:child_process'
2-
import { validateUrl } from './utils'
2+
import { getExecutablePath, validateUrl } from './utils'
33
/**
44
* @typedef LightpandaFetchOptions
55
* @type {object}
@@ -33,6 +33,7 @@ export const fetch = (url: string, options: LightpandaFetchOptions = defaultOpti
3333

3434
return new Promise<Buffer | string>((resolve, reject) => {
3535
try {
36+
const executablePath = getExecutablePath()
3637
const flags = [
3738
{ flag: '--dump', condition: dump },
3839
{ flag: '--insecure_disable_tls_host_verification', condition: disableHostVerification },
@@ -41,7 +42,7 @@ export const fetch = (url: string, options: LightpandaFetchOptions = defaultOpti
4142
.map(f => (f.condition ? f.flag : ''))
4243
.join(' ')
4344

44-
const e = execSync(`./lightpanda fetch ${flags} ${url}`)
45+
const e = execSync(`${executablePath} fetch ${flags} ${url}`)
4546

4647
if (dump) {
4748
resolve(e.toString())

packages/browser/src/serve.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type ChildProcessWithoutNullStreams, spawn } from 'node:child_process'
2-
import { validatePort, validateUrl } from './utils'
2+
import { getExecutablePath, validatePort, validateUrl } from './utils'
33
/**
44
* @typedef LightpandaServeOptions
55
* @type {object}
@@ -38,6 +38,7 @@ export const serve = (options: LightpandaServeOptions = defaultOptions) => {
3838
}
3939

4040
return new Promise<ChildProcessWithoutNullStreams>((resolve, reject) => {
41+
const executablePath = getExecutablePath()
4142
const flags = [
4243
{ flag: '--host', value: host },
4344
{ flag: '--port', value: port },
@@ -52,7 +53,7 @@ export const serve = (options: LightpandaServeOptions = defaultOptions) => {
5253
.flatMap(f => (f.value ? [f.flag, !f.flagOnly ? f.value.toString() : ''] : ''))
5354
.filter(f => f !== '')
5455

55-
const process = spawn('./lightpanda', ['serve', ...flags])
56+
const process = spawn(executablePath, ['serve', ...flags])
5657

5758
process.on('spawn', async () => {
5859
console.info("🐼 Running Lightpanda's CDP server…", {

packages/browser/src/utils.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
import os from 'node:os'
2+
3+
export const DEFAULT_CACHE_FOLDER = `${os.homedir()}/.cache/lightpanda-node`
4+
export const BINARY_NAME = 'lightpanda'
5+
6+
export const USER_EXECUTABLE_PATH = process.env.LIGHTPANDA_EXECUTABLE_PATH
7+
export const DEFAULT_EXECUTABLE_PATH = `${DEFAULT_CACHE_FOLDER}/${BINARY_NAME}`
8+
9+
/**
10+
* Validate a URL structure
11+
* @param {string} url URL to validate
12+
*/
113
export const validateUrl = (url: string): void => {
214
if (!url || typeof url !== 'string') {
315
throw new Error(`URL is required and must be a string ${url}`)
@@ -14,6 +26,10 @@ export const validateUrl = (url: string): void => {
1426
}
1527
}
1628

29+
/**
30+
* Validate a port number
31+
* @param {number} port Port number to validate
32+
*/
1733
export const validatePort = (port: number): void => {
1834
if (!port || typeof port !== 'number') {
1935
throw new Error(`Port is required and must be a number ${port}`)
@@ -23,3 +39,10 @@ export const validatePort = (port: number): void => {
2339
throw new Error(`Port should be a positive number ${port}`)
2440
}
2541
}
42+
43+
/**
44+
* Get executable path
45+
*/
46+
export const getExecutablePath = () => {
47+
return USER_EXECUTABLE_PATH ?? DEFAULT_EXECUTABLE_PATH
48+
}

0 commit comments

Comments
 (0)