OverviewFilesCommitsIssuesDocsReleasesPeers

pearbrowser-desktop commits / e32a5f8

migrate desktop host to Pear v3 runtime
e32a5f8f2a2e1bc950b08f4b1decd82dda3439d1
by bigdestiny2 <33146784+bigdestiny2@users.noreply.github.com> · 2026-07-23T00:12:26.000Z

Changed files (35) +655 -834

appling/README.md +1 -1
……@@ -31,7 +31,7 @@ whose subject matches `PEARBROWSER_WINDOWS_SIGNING_SUBJECT`.
3131
3232Run `npm run check:appling-release -- --tag v0.5.0` before cutting a release.
3333It verifies that `CMakeLists.txt` uses the same version as the desktop package
34and the same Pear key as `pear.json`.
34and the same Pear OTA update channel as `package.json`.
3535
3636Run `npm run check:native-signing -- --require-public-trust` from the repo root
3737before publishing public desktop assets. It validates that the macOS Developer
backend/index.js +2 -2
……@@ -1265,7 +1265,6 @@ rpc.handle(C.CMD_RESET_APP, async () => {
12651265
12661266 // Give the reply a tick to reach the UI before we exit.
12671267 setTimeout(() => {
1268 try { if (typeof Pear !== 'undefined' && Pear.exit) Pear.exit() } catch {}
12691268 try { Bare.exit?.() } catch {}
12701269 }, 200)
12711270
……@@ -3420,7 +3419,8 @@ async function cleanupOldData () {
34203419Bare.on('suspend', () => IPC.unref())
34213420Bare.on('resume', () => IPC.ref())
34223421
3423// When main closes the IPC pipe (window closed, Pear.teardown), run
3422// When the native host closes the IPC pipe (for example, when its window
3423// closes), run
34243424// a clean shutdown so Corestore flushes, Hyperswarm closes, and
34253425// rocksdb releases its LOCK. Without this the next launch trips on
34263426// EADDRINUSE or a stale LOCK.
backend/pear-adapter.cjs +5 -7
……@@ -2,14 +2,12 @@
22 * Pear adapter for PearBrowser backend.
33 *
44 * The original backend assumes a mobile BareKit host that injects
5 * `BareKit.IPC` (a duplex stream) before the backend loads. In the
6 * desktop Pear fork we run the backend in the renderer for M1 and
7 * fake that injection with an in-memory pipe pair.
5 * `BareKit.IPC` (a duplex stream) before the backend loads. For the
6 * desktop worker adapter we use an in-memory pipe pair.
87 *
9 * Migration to a real 2-process layout (pear-run + pear-pipe) only
10 * has to swap the two "sides" returned here for a real `bare-pipe`
11 * duplex; the backend code above and the UI RPC client below don't
12 * change.
8 * The v3 Electron host owns the worker lifecycle. If it later provides a
9 * native duplex, only the two sides returned here need replacing; the backend
10 * and renderer RPC contracts remain unchanged.
1311 */
1412
1513const EventEmitter = require('bare-events')
docs/BROWSER_PARITY_PLAN.md +8 -8
……@@ -1,6 +1,6 @@
11# PearBrowser → mainstream-browser parity plan
22
3Status: Phases 1–3 shipped with gates closed; Phase 4 clearnet proxy + session-bridge facade shipped; Phase 5 privacy ladder shipped (HTTPS-only, tracking strip, farbling, cookie isolation in proxy mode). P2P distribution live 2026-07-16: filter-list drive subscriptions (`shield-list-sync.cjs`) and plugin installs from drives (`plugin-drive-loader.cjs` with the capability-escalation guard), plus the plugin catalogue (`plugin-catalog.cjs`, anonGPT in the builtin seed). All four distribution drives published, pinned, and fresh-peer verified — keys in `filter-lists/README.md`. Remaining: the native pear-electron session.webRequest bridge for direct-mode shields.
3Status: Phases 1–3 shipped with gates closed; Phase 4 clearnet proxy + session-bridge facade shipped; Phase 5 privacy ladder shipped (HTTPS-only, tracking strip, farbling, cookie isolation in proxy mode). P2P distribution live 2026-07-16: filter-list drive subscriptions (`shield-list-sync.cjs`) and plugin installs from drives (`plugin-drive-loader.cjs` with the capability-escalation guard), plus the plugin catalogue (`plugin-catalog.cjs`, anonGPT in the builtin seed). All four distribution drives published, pinned, and fresh-peer verified — keys in `filter-lists/README.md`. The v3 native host now owns Electron directly. Remaining: wire the existing ContentShield contract to Electron's native `session.webRequest` only after a dedicated policy/RPC boundary and cross-platform GUI evidence are in place.
44Date: 2026-07-16
55
66The goal: make PearBrowser as capable a daily browser as Brave — ad blocking,
……@@ -13,9 +13,9 @@ browser would do. The constraints below decide everything.
1313
1414## 1. Ground truth: what PearBrowser is today
1515
16- **Runtime split.** A Bare main process runs the backend
17 (`backend/index.js`); a prebuilt pear-electron renderer runs the React UI
18 (`ui/shell.js`). They speak length-prefixed JSON RPC over a loopback
16- **Runtime split.** An Electron main process owns the window and lifecycle;
17 an embedded Pear OTA worker runs the Bare backend (`index.js`); the renderer
18 hosts the UI (`ui/shell.js`). They speak length-prefixed JSON RPC over a loopback
1919 WebSocket (ports 9876–9880).
2020- **Tabs are sandboxed `<iframe>`s**, not Electron `<webview>`s
2121 (`ui/shell.js`, `.webview` iframes; sandbox
……@@ -28,10 +28,10 @@ browser would do. The constraints below decide everything.
2828 injects `<base>`, tokens, and `window.pear.*` shims into every served HTML
2929 document, and re-writes the page CSP to hash-authorize exactly the scripts
3030 the browser injects (`injectCspShimHashes`) — never `unsafe-inline`.
31- **Chromium's net stack is out of reach.** The Electron main process ships
32 inside pear-electron's prebuilt boot bundle. App code cannot register
33 `session.webRequest`, `declarativeNetRequest`, or protocol handlers without
34 forking that bundle.
31- **Chromium's net stack is host-owned, but not yet policy-wired.** The
32 Electron main process can register `session.webRequest`, but it must not do
33 so until the browser's existing shield policy is exposed through a narrow,
34 testable native-host boundary.
3535- **Clearnet `https://` sites are not browsable.** `CMD_NAVIGATE` maps
3636 non-loopback URLs onto `/hyper/<host>/…`, which 400s for non-drive hosts.
3737- **Capability permissions already exist.** Drive manifests declare
docs/NATIVE_RELEASE_PACKAGING.md +1 -1
……@@ -109,7 +109,7 @@ toolchain that was tested locally.
109109`scripts/check-appling-release.mjs` fails the workflow when:
110110
111111- the requested tag does not match `package.json` version
112- `appling/CMakeLists.txt` does not match the production Pear key in `pear.json`
112- `appling/CMakeLists.txt` does not match the Pear OTA update channel in `package.json`
113113- the appling CMake version is stale
114114- the appling package no longer exposes `generate`, `build`, and `package`
115115- the native wrapper toolchain lockfile, pinned Bare headers, macOS ICNS asset,
docs/PEAR_V3_MIGRATION.md +27 -10
……@@ -15,11 +15,21 @@ that presents verified applications and installs as distinct user actions.
1515
1616## Runtime boundary
1717
18The browser’s embedded runtime starts only a bundled local worker using the
19equivalent of `PearRuntime.run(require.resolve('./worker.js'))`. A remote
20catalogue link is discovery metadata, not executable worker input. The
21renderer cannot invoke an installer or runtime directly; those operations stay
22in the privileged local backend and require explicit user confirmation.
18PearBrowser v3 is a conventional Electron application. The Electron main
19process owns windows, OS lifecycle, and the narrow preload bridge; it starts
20only the bundled `workers/main.js` through
21`PearRuntime.run(require.resolve(...))`. That worker owns the Bare backend and
22the authenticated localhost RPC service.
23
24The renderer receives a freshly generated, per-launch session token through
25the context-isolated preload bridge. It cannot invoke the runtime, install an
26application, or obtain Node integration. A remote catalogue link remains
27discovery metadata, never a `PearRuntime.run()` input.
28
29The `package.json#upgrade` field is a v3 OTA deployment identity, not a
30browser-launch affordance. It must move to the project’s production multisig
31link before a public v3 release. The existing value is retained only to keep
32the source buildable while the signing quorum establishes that channel.
2333
2434## Data continuity
2535
……@@ -30,8 +40,15 @@ evidence, not a substitute for package signature or local data validation.
3040
3141## Release gate
3242
33This source branch has removed remote legacy execution. Before it can be
34promoted as a v3 native runtime build, the pinned `pear-runtime@1.3.1` host,
35local worker boot/shutdown test, supported native package targets, and an
36approved v3 package installer flow must all be present and independently
37verified.
43This source branch contains the pinned `pear-runtime@1.3.1` native host and
44local-worker boundary, and tests the source contract. Promotion remains
45blocked until all of the following have independent evidence:
46
47- a real Electron launch plus worker/backend handshake on each supported OS;
48- a v3 `pear build` deployment assembled from those signed OS artifacts;
49- stage → provision → multisig release evidence for the production upgrade
50 link (the signing quorum is human-controlled);
51- storage discovery, migration, validation, and rollback evidence for an
52 existing v2 profile; and
53- installer/update/recovery UX evidence that treats HiveRelay as availability,
54 never package attestation.
docs/QVAC_NATIVE_AI.md +3 -2
……@@ -136,8 +136,9 @@ QVAC_SMOKE_MODEL_PATH=/absolute/path/to/model.gguf \
136136This local path is host configuration for the diagnostic fixture only. An app
137137still chooses a browser-approved alias and can never submit a path to QVAC.
138138
139`npm run smoke:qvac:pear` exercises the same terminal fixture through the Pear
140launcher when the local Pear runtime is fully installed.
139`npm run smoke:qvac:pear` is retained as a compatibility alias for the native
140Bare-worker smoke. PearBrowser's Electron host owns the embedded Pear OTA
141worker; it never uses a CLI launcher for this check.
141142
142143## Current proof
143144
docs/TEST-COMMAND-MATRIX-2026-06-23.md +3 -3
……@@ -68,9 +68,9 @@ covered by `npm test`.
6868| --- | --- |
6969| `node scripts/runtime-rpc-smoke.mjs --timeout 20000 --max-storage-percent 100 --json` | Diagnostic WebSocket smoke against an already-running app. Requires PearBrowser to be launched first; public smoke should fail if the profile is over quota |
7070| `PEARBROWSER_RPC_DIAGNOSTIC_TOKEN=<random> node scripts/release-rpc-story-smoke.mjs --timeout 60000 --request-timeout 80000 --desktop-gui-stories --site-story --json` | Nonvisual story preflight against an app launched with the same `PEARBROWSER_RPC_DIAGNOSTIC_TOKEN`. Loads the release catalogues, fetches/reloads the PearBrowser homepage through the local proxy, verifies drive-info/site metadata, validates featured catalogue rows, confirms Peercord remains window-only, proves catalogue search/action rows, opens a safe catalogue-row Hyperdrive app through Browse, proves local search first-paint, curated/petname naming, bookmark/session round-trips with diagnostic reconnect, runs the Nostr trusted-contact proof, and emits release-evidence row suggestions. With `--site-story` it publishes/fetches/deletes a temporary site with HiveRelay unseed cleanup. It does not launch third-party Pear apps or approve trust prompts |
71| `npm run start` | Interactive Pear dev launch: `pear run --dev .` |
72| `npm run run` | Interactive Pear launch: `pear run .` |
73| `pear run pear://tco5k7h38uoxatedp1wongdbhjxow1x7jiwm3t1i9cujbebhsbty` | Production browser launch/manual smoke gate |
71| `npm run start` | Interactive native Electron development launch with the embedded Pear OTA worker. |
72| `npm run run` | Interactive native Electron launch with the embedded Pear OTA worker. |
73| Signed PearBrowser native package | Production browser launch/manual smoke gate; the package contains the host and resolves its approved OTA update channel locally. |
7474
7575Use `docs/MANUAL_RELEASE_SMOKE_2026-06-23.md` for GUI proof. Record machine,
7676commit SHA, screenshots/logs, and pass/fail notes beside each checked item.
electron/main.cjs +103 -0
……@@ -0,0 +1,103 @@
1// Native v3 host. Electron owns application lifecycle and Pear OTA owns only
2// the embedded Bare backend/update worker; there is no `pear run` launch path.
3const { app, BrowserWindow, ipcMain } = require('electron')
4const crypto = require('node:crypto')
5const os = require('node:os')
6const path = require('node:path')
7const PearRuntime = require('pear-runtime')
8const pkg = require('../package.json')
9
10const sessionToken = crypto.randomBytes(32).toString('hex')
11const appName = pkg.productName || pkg.name
12let workerPipe = null
13let pearRuntime = null
14let quitting = false
15
16ipcMain.on('pearbrowser:runtime-session', (event) => {
17 event.returnValue = sessionToken
18})
19
20ipcMain.handle('pearbrowser:open-devtools', (event) => {
21 event.sender.openDevTools({ mode: 'detach' })
22})
23
24function storagePath () {
25 if (!app.isPackaged) return path.join(os.tmpdir(), 'pearbrowser-desktop')
26 return app.getPath('userData')
27}
28
29function appBundlePath () {
30 if (!app.isPackaged) return null
31 if (process.platform === 'linux' && process.env.APPIMAGE) return process.env.APPIMAGE
32 if (process.platform === 'win32') return process.execPath
33 return path.join(process.resourcesPath, '..', '..')
34}
35
36async function startBackendWorker () {
37 if (workerPipe) return workerPipe
38 pearRuntime = new PearRuntime({
39 dir: storagePath(),
40 name: appName,
41 version: pkg.version,
42 upgrade: pkg.upgrade,
43 app: appBundlePath(),
44 updates: app.isPackaged
45 })
46 pearRuntime.on('error', (error) => console.error('Pear OTA runtime error:', error))
47 pearRuntime.updater.on('updating', () => console.log('PearBrowser update is downloading'))
48 pearRuntime.updater.on('updated', () => console.log('PearBrowser update is ready; restart to apply it'))
49 // OTA readiness is deliberately non-blocking: a browser must still open
50 // offline using its installed build and local data.
51 pearRuntime.ready().catch((error) => console.error('Pear OTA initialization failed:', error))
52
53 const worker = pearRuntime.run(require.resolve('../workers/main.js'), [pearRuntime.storage, sessionToken])
54 workerPipe = worker
55 worker.once('exit', (code) => {
56 workerPipe = null
57 if (!quitting) console.error(`PearBrowser backend worker exited unexpectedly (${code})`)
58 })
59 return workerPipe
60}
61
62async function createWindow () {
63 const window = new BrowserWindow({
64 width: 1280,
65 height: 800,
66 minWidth: 920,
67 minHeight: 600,
68 backgroundColor: '#f6f8f7',
69 webPreferences: {
70 preload: path.join(__dirname, 'preload.cjs'),
71 sandbox: true,
72 nodeIntegration: false,
73 contextIsolation: true
74 }
75 })
76
77 await window.loadFile(path.join(__dirname, '..', 'index.html'))
78}
79
80const singleInstance = app.requestSingleInstanceLock()
81if (!singleInstance) {
82 app.quit()
83} else {
84 app.whenReady().then(async () => {
85 await startBackendWorker()
86 await createWindow()
87 app.on('activate', async () => {
88 if (BrowserWindow.getAllWindows().length === 0) await createWindow()
89 })
90 }).catch((error) => {
91 console.error('Failed to start PearBrowser:', error)
92 app.quit()
93 })
94
95 app.on('window-all-closed', () => {
96 if (process.platform !== 'darwin') app.quit()
97 })
98 app.on('before-quit', () => {
99 quitting = true
100 try { workerPipe?.destroy() } catch {}
101 pearRuntime?.close().catch((error) => console.error('Pear OTA runtime shutdown failed:', error))
102 })
103}
electron/preload.cjs +6 -0
……@@ -0,0 +1,6 @@
1const { contextBridge, ipcRenderer } = require('electron')
2
3contextBridge.exposeInMainWorld('pearbrowserRuntime', {
4 sessionToken: ipcRenderer.sendSync('pearbrowser:runtime-session'),
5 openDevTools: () => ipcRenderer.invoke('pearbrowser:open-devtools')
6})
history/legacy-v2-release-identifiers.json +8 -0
……@@ -0,0 +1,8 @@
1{
2 "historical": true,
3 "purpose": "Migration lookup only. These identifiers are never passed to an executable launch path.",
4 "links": {
5 "production": "pear://tco5k7h38uoxatedp1wongdbhjxow1x7jiwm3t1i9cujbebhsbty",
6 "provisionTarget": "pear://pdsd1p3m1xsz8aofyndbwux5hqs19h8uswnsrfee5cz8sj9pmj4o"
7 }
8}
index.js +15 -37
……@@ -1,5 +1,3 @@
1import Runtime from 'pear-electron'
2import Bridge from 'pear-bridge'
31import ws from 'bare-ws'
42import http from 'bare-http1'
53import fs from 'bare-fs'
……@@ -26,9 +24,13 @@ const { authorizeRpcWebSocket, DiagnosticRpcRouter } = rpcWebSocketAuth
2624const RPC_PORT_BASE = 9876
2725const RPC_PORT_COUNT = 5
2826const RENDERER_RECONNECT_GRACE_MS = 8000
29const rpcSessionToken = String(Pear.config?.startId || '')
27// Pear v3 executes this file as a worker owned by `pear-runtime`. The Electron
28// host supplies the two values below before loading us; unlike the retired
29// `pear run` host, no ambient global `Pear` API is involved.
30const runtimeContext = globalThis.PearBrowserRuntime || {}
31const rpcSessionToken = String(runtimeContext.sessionToken || '')
3032const diagnosticToken = String(env.PEARBROWSER_RPC_DIAGNOSTIC_TOKEN || '')
31if (!rpcSessionToken) throw new Error('Pear runtime did not provide a per-launch RPC session token')
33if (!rpcSessionToken) throw new Error('PearBrowser v3 host did not provide a per-launch RPC session token')
3234
3335// --- 1. Boot the backend in this Bare main process. ---
3436//
……@@ -41,8 +43,8 @@ if (!rpcSessionToken) throw new Error('Pear runtime did not provide a per-launch
4143// Instead: catch the boot failure, still bind the WS server, and when
4244// the renderer connects send it a structured `backend-boot-failed`
4345// event so the UI can render a clear error. The dev logs also get a
44// loud banner that makes the cause obvious in `pear run --dev` output.
45const storagePath = (Pear.config?.storage || '.') + '/pearbrowser-storage'
46// loud banner that makes the cause obvious in the native host logs.
47const storagePath = String(runtimeContext.storagePath || '.') + '/pearbrowser-storage'
4648const ollamaModels = env.PEARBROWSER_QVAC_OLLAMA === '0'
4749 ? {}
4850 : discoverOllamaQwenModels({
……@@ -92,10 +94,9 @@ try {
9294 console.error('display this error instead of "could not reach backend".')
9395 console.error('')
9496 console.error('Common causes:')
95 console.error(' • Staged drive is incomplete on disk (relay partial pin)')
96 console.error(' Try: rm -rf "$HOME/Library/Application Support/pear/by-dkey/00f61fc1473b9d01a199833fc96e76d5e99000c603ec697bc842f8d978538f4d"')
97 console.error(' then re-run `pear run pear://tco5...`')
98 console.error(' • Pear runtime too old — update with: pear run pear://runtime')
97 console.error(' • The local PearBrowser installation is incomplete')
98 console.error(' Reinstall the verified native package, then relaunch it.')
99 console.error(' • The embedded Pear OTA runtime is incompatible with this OS/arch')
99100 console.error(' • Missing native addon for this OS/arch')
100101 console.error('========================================================')
101102 console.error('')
……@@ -294,16 +295,10 @@ if (!rpcServer) {
294295 throw new Error(`No free WS RPC port in ${RPC_PORT_BASE}-${RPC_PORT_BASE + RPC_PORT_COUNT - 1}`)
295296}
296297
297// --- 3. Open the UI window via pear-electron. ---
298const runtime = new Runtime()
299const bridge = new Bridge()
300await bridge.ready()
301const pipe = runtime.start({ bridge })
302
303// Real shutdown: when the renderer pipe ends, close + force-exit.
304// Pear.teardown alone didn't fire consistently; hooking every
305// exit signal so lingering processes stop blocking subsequent
306// launches with EADDRINUSE / rocksdb LOCK conflicts.
298// --- 3. Worker lifecycle. ---
299// The Electron host owns windows and terminates this Pear OTA worker when the
300// last window exits. Keep the backend cleanup local to the worker rather than
301// relying on Pear v2's renderer pipe or global teardown hooks.
307302let tornDown = false
308303function teardown (reason) {
309304 if (tornDown) return
……@@ -314,33 +309,16 @@ function teardown (reason) {
314309 try { rpcServer?.close() } catch {}
315310 try { client?.end?.() } catch {}
316311 try { backendPipe.end?.() } catch {}
317 try { pipe?.end?.() } catch {}
318312 // Hard-exit fast: hypercore/corestore can hold the event loop
319313 // open for tens of seconds on graceful close, and that's what
320314 // was letting zombies survive. 300ms is plenty for our WS
321315 // client to flush.
322316 setTimeout(() => {
323317 console.log('[teardown] hard-exit')
324 try { Pear.exit?.(0) } catch {}
325318 try { Bare.exit?.(0) } catch {}
326319 try { process?.exit?.(0) } catch {}
327320 }, 300)
328321}
329// pear-electron's runtime.start() return shape varies across versions:
330// older builds returned a duplex pipe (.on/.end), newer ones return a
331// plain object. Detect what we got and only attach listeners that exist.
332// The WS-renderer-close path is our reliable shutdown trigger; these
333// pipe listeners are belt-and-braces so any other exit signal still
334// teardowns. Wrap each in try/catch so an unsupported runtime never
335// throws an [uncaughtException] at boot.
336if (pipe && typeof pipe.on === 'function') {
337 try { pipe.on('close', () => teardown('pipe close')) } catch {}
338 try { pipe.on('end', () => teardown('pipe end')) } catch {}
339 try { pipe.on('error', (err) => teardown('pipe error: ' + (err && err.message))) } catch {}
340} else {
341 console.log('[boot] runtime.start() returned non-emitter pipe; using WS-close + Pear.teardown only')
342}
343try { Pear.teardown(() => teardown('Pear.teardown')) } catch {}
344322try { Bare.on?.('beforeExit', () => teardown('beforeExit')) } catch {}
345323try { Bare.on?.('exit', () => teardown('exit')) } catch {}
346324try { process?.on?.('SIGTERM', () => teardown('SIGTERM')) } catch {}
package-lock.json +324 -639
……@@ -28,6 +28,7 @@
2828 "bip39-mnemonic": "^2.5.0",
2929 "blind-pairing": "^2.3.1",
3030 "corestore": "^7.9.2",
31 "electron": "43.2.0",
3132 "framed-stream": "^1.0.0",
3233 "htm": "^3.1.1",
3334 "hyperbee": "^2.27.3",
……@@ -38,9 +39,7 @@
3839 "p2p-hiverelay": "latest",
3940 "p2p-hiverelay-client": "latest",
4041 "p2p-hiverelay-verifier": "latest",
41 "pear-bridge": "1.2.5",
42 "pear-electron": "1.7.28",
43 "pear-run": "2.0.0",
42 "pear-runtime": "1.3.1",
4443 "react": "^18.3.1",
4544 "react-dom": "^18.3.1",
4645 "schema-sheets": "^3.1.1"
……@@ -49,6 +48,35 @@
4948 "bare": "1.30.3"
5049 }
5150 },
51 "node_modules/@electron-internal/extract-zip": {
52 "version": "1.0.4",
53 "resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.4.tgz",
54 "integrity": "sha512-Zr1Vs7E9tpCNhZHDAbFVXc2gEVCG9RqPDjrno5+bdgB6LRAuvgyMHJut4NCVyYwtAieapMzc3fiQ3CSTi75ARg==",
55 "license": "BSD-2-Clause",
56 "engines": {
57 "node": ">=22.12.0"
58 }
59 },
60 "node_modules/@electron/get": {
61 "version": "5.0.0",
62 "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.0.0.tgz",
63 "integrity": "sha512-pjoBpru1KdEtcExBnuHAP1cAc/5faoedw0hzJkL3o4/IJp7HNF1+fbrdxT3gMYRX2oJfvnA/WXeCTVQpYYxyJA==",
64 "license": "MIT",
65 "dependencies": {
66 "debug": "^4.1.1",
67 "env-paths": "^3.0.0",
68 "graceful-fs": "^4.2.11",
69 "progress": "^2.0.3",
70 "semver": "^7.6.3",
71 "sumchecker": "^3.0.1"
72 },
73 "engines": {
74 "node": ">=22.12.0"
75 },
76 "optionalDependencies": {
77 "undici": "^7.24.4"
78 }
79 },
5280 "node_modules/@grpc/grpc-js": {
5381 "version": "1.14.4",
5482 "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.4.tgz",
……@@ -1022,18 +1050,6 @@
10221050 "undici-types": "~8.3.0"
10231051 }
10241052 },
1025 "node_modules/acorn": {
1026 "version": "8.16.0",
1027 "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
1028 "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
1029 "license": "MIT",
1030 "bin": {
1031 "acorn": "bin/acorn"
1032 },
1033 "engines": {
1034 "node": ">=0.4.0"
1035 }
1036 },
10371053 "node_modules/adaptive-timeout": {
10381054 "version": "1.0.1",
10391055 "resolved": "https://registry.npmjs.org/adaptive-timeout/-/adaptive-timeout-1.0.1.tgz",
……@@ -1261,6 +1277,17 @@
12611277 "bare-inspect": "^3.1.2"
12621278 }
12631279 },
1280 "node_modules/bare-broadcast-channel": {
1281 "version": "0.2.0",
1282 "resolved": "https://registry.npmjs.org/bare-broadcast-channel/-/bare-broadcast-channel-0.2.0.tgz",
1283 "integrity": "sha512-MuAwdKWr4cSjNwqvbE3tA9Wn6w69q6iXYnP2Wb0nlDa6sKNSMSfY7LXkV4FzWlq9JFP9d0HkCAKPboTLKnUfWQ==",
1284 "license": "Apache-2.0",
1285 "dependencies": {
1286 "bare-events": "^2.0.0",
1287 "bare-stream": "^2.7.0",
1288 "bare-structured-clone": "^1.4.0"
1289 }
1290 },
12641291 "node_modules/bare-buffer": {
12651292 "version": "3.6.2",
12661293 "resolved": "https://registry.npmjs.org/bare-buffer/-/bare-buffer-3.6.2.tgz",
……@@ -1288,6 +1315,20 @@
12881315 }
12891316 }
12901317 },
1318 "node_modules/bare-channel": {
1319 "version": "5.2.4",
1320 "resolved": "https://registry.npmjs.org/bare-channel/-/bare-channel-5.2.4.tgz",
1321 "integrity": "sha512-enkaOtvXUiZsLBSbataxV/QBjehCOK+SUTd2JQWUYW2iIOufpPu9jyZ9bqJqkEquktrK/rpEMVEmKsPzoci/sA==",
1322 "license": "Apache-2.0",
1323 "dependencies": {
1324 "bare-events": "^2.0.0",
1325 "bare-stream": "^2.7.0",
1326 "bare-structured-clone": "^1.4.0"
1327 },
1328 "engines": {
1329 "bare": ">=1.7.0"
1330 }
1331 },
12911332 "node_modules/bare-crypto": {
12921333 "version": "1.15.3",
12931334 "resolved": "https://registry.npmjs.org/bare-crypto/-/bare-crypto-1.15.3.tgz",
……@@ -1306,17 +1347,6 @@
13061347 }
13071348 }
13081349 },
1309 "node_modules/bare-daemon": {
1310 "version": "1.2.4",
1311 "resolved": "https://registry.npmjs.org/bare-daemon/-/bare-daemon-1.2.4.tgz",
1312 "integrity": "sha512-pyWmqqsN9x2RNzXFpHObyU8+9vgFL7q63Nhtk+xRTXcWL/LkZrYpLmIpYlyPzwZrT2vL+lrjBwVMyCljThfC+A==",
1313 "license": "Apache-2.0",
1314 "dependencies": {
1315 "bare-env": "^3.0.0",
1316 "bare-os": "^3.6.2",
1317 "require-addon": "^1.1.0"
1318 }
1319 },
13201350 "node_modules/bare-debug-log": {
13211351 "version": "2.0.0",
13221352 "resolved": "https://registry.npmjs.org/bare-debug-log/-/bare-debug-log-2.0.0.tgz",
……@@ -1574,9 +1604,9 @@
15741604 }
15751605 },
15761606 "node_modules/bare-module-lexer": {
1577 "version": "1.5.3",
1578 "resolved": "https://registry.npmjs.org/bare-module-lexer/-/bare-module-lexer-1.5.3.tgz",
1579 "integrity": "sha512-URLPza0jP3aVzeIX5MDKAl5tGH7zLW1dNCVmSvg3so6PM0/HhoDk2AfVQVeTFJ1xZaxFfaLuGa43q8uC1MmY1g==",
1607 "version": "1.6.3",
1608 "resolved": "https://registry.npmjs.org/bare-module-lexer/-/bare-module-lexer-1.6.3.tgz",
1609 "integrity": "sha512-NQY7cnPV3GZlHJphX4nXmPdNPER/Tp17pVi9/he2ODw/GNZ7FXzrZlrS7WMF8zbtWigqW/NMc9aQc2BH8UJXqA==",
15801610 "license": "Apache-2.0",
15811611 "dependencies": {
15821612 "require-addon": "^1.0.2"
……@@ -1607,6 +1637,30 @@
16071637 }
16081638 }
16091639 },
1640 "node_modules/bare-module-traverse": {
1641 "version": "2.4.4",
1642 "resolved": "https://registry.npmjs.org/bare-module-traverse/-/bare-module-traverse-2.4.4.tgz",
1643 "integrity": "sha512-zK4bDxqeD15Tvu/C5B1Mi/epl9PavjIhU3SVh5RhDb4Hpet6applPVX8Q9rinu7nT80yzgSSlBn0exzJaNXv0A==",
1644 "license": "Apache-2.0",
1645 "dependencies": {
1646 "bare-addon-resolve": "^1.5.0",
1647 "bare-mime": "^1.0.0",
1648 "bare-module-lexer": "^1.6.0",
1649 "bare-module-resolve": "^1.7.0"
1650 },
1651 "peerDependencies": {
1652 "bare-buffer": "*",
1653 "bare-url": "*"
1654 },
1655 "peerDependenciesMeta": {
1656 "bare-buffer": {
1657 "optional": true
1658 },
1659 "bare-url": {
1660 "optional": true
1661 }
1662 }
1663 },
16101664 "node_modules/bare-net": {
16111665 "version": "2.3.1",
16121666 "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.3.1.tgz",
……@@ -1638,9 +1692,9 @@
16381692 }
16391693 },
16401694 "node_modules/bare-pipe": {
1641 "version": "4.1.5",
1642 "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.1.5.tgz",
1643 "integrity": "sha512-6OfxaG8JSkRh3Gc4hzHRsxNt+yu2PpN7lrv1V+T78GdknWQkVGwiEvu4m+1nbfk8cMVQ0TGxRvQ90XA4rhnTuw==",
1695 "version": "4.2.2",
1696 "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.2.2.tgz",
1697 "integrity": "sha512-Wkf6//CmKS8inHrkgi3X/xNMeaGfs2I0ayLM0B8cbPB4DxYHcoes6Ng+muCBfXNIJ9qmEjwDDJjAUz7nRxxjgQ==",
16441698 "license": "Apache-2.0",
16451699 "dependencies": {
16461700 "bare-events": "^2.0.0",
……@@ -1678,16 +1732,6 @@
16781732 "integrity": "sha512-pUtEM6JrX53MbEJFwO92F0Ch7BwZ67KD7LyglcB8/tvkkVdwTgN1f7oIklRe+NTT/WCYZgwjDFYS9efBxDSq8g==",
16791733 "license": "Apache-2.0"
16801734 },
1681 "node_modules/bare-readline": {
1682 "version": "1.3.1",
1683 "resolved": "https://registry.npmjs.org/bare-readline/-/bare-readline-1.3.1.tgz",
1684 "integrity": "sha512-QtSU4ZfgQcDI6AQssjDFqTiRe4rCiciMn+Yqx6siMJZBIftAIFrNSOK0sa5SBrmNv/a7CD9Dm0onUDCRyn5Fdg==",
1685 "license": "Apache-2.0",
1686 "dependencies": {
1687 "bare-ansi-escapes": "^2.0.0",
1688 "bare-stream": "^2.0.0"
1689 }
1690 },
16911735 "node_modules/bare-rpc": {
16921736 "version": "1.3.8",
16931737 "resolved": "https://registry.npmjs.org/bare-rpc/-/bare-rpc-1.3.8.tgz",
……@@ -2026,21 +2070,6 @@
20262070 "bare": "bin/bare.exe"
20272071 }
20282072 },
2029 "node_modules/bare-runtime/node_modules/bare-pipe": {
2030 "version": "4.2.2",
2031 "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.2.2.tgz",
2032 "integrity": "sha512-Wkf6//CmKS8inHrkgi3X/xNMeaGfs2I0ayLM0B8cbPB4DxYHcoes6Ng+muCBfXNIJ9qmEjwDDJjAUz7nRxxjgQ==",
2033 "dev": true,
2034 "license": "Apache-2.0",
2035 "peer": true,
2036 "dependencies": {
2037 "bare-events": "^2.0.0",
2038 "bare-stream": "^2.0.0"
2039 },
2040 "engines": {
2041 "bare": ">=1.16.0"
2042 }
2043 },
20442073 "node_modules/bare-runtime/node_modules/bare-subprocess": {
20452074 "version": "6.1.0",
20462075 "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-6.1.0.tgz",
……@@ -2069,36 +2098,54 @@
20692098 }
20702099 }
20712100 },
2072 "node_modules/bare-runtime/node_modules/bare-tcp": {
2073 "version": "2.5.2",
2074 "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.5.2.tgz",
2075 "integrity": "sha512-9SAF0r+p5w3QxsI9BGBqj/0VlNwJGkEj/1AAJi+4Pl0W7ke2JiYmt7GhJss/uaEnY0s4/N/A/Os6Dr+dVfVzyQ==",
2076 "dev": true,
2101 "node_modules/bare-semver": {
2102 "version": "1.0.3",
2103 "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.3.tgz",
2104 "integrity": "sha512-HS/A30bi2+PiRJfU6R4+Kp+6KeLSCSByjYM2iiobOKzLAvtu1CT+S8xWfiU7wz0erknjkUoC+yXy108tzIuP5Q==",
2105 "license": "Apache-2.0"
2106 },
2107 "node_modules/bare-sidecar": {
2108 "version": "0.5.3",
2109 "resolved": "https://registry.npmjs.org/bare-sidecar/-/bare-sidecar-0.5.3.tgz",
2110 "integrity": "sha512-TO/FHNUWgNEfDGiqrvmYT7+1ZxRpa4J0fWQsdVIjh5FY5xC+PocdMQPw/LiTp7iyhTUatZEeTDWr4l8DQ3jaeA==",
20772111 "license": "Apache-2.0",
2078 "peer": true,
20792112 "dependencies": {
2080 "bare-dns": "^2.0.4",
2113 "bare-fs": "^4.5.1",
2114 "bare-module": "^6.1.3",
2115 "bare-path": "^3.0.0",
2116 "bare-pipe": "^4.1.3",
2117 "bare-stream": "^2.7.0",
2118 "bare-subprocess": "^6.0.0",
2119 "bare-url": "^2.3.2",
2120 "require-asset": "^1.1.0"
2121 }
2122 },
2123 "node_modules/bare-sidecar/node_modules/bare-subprocess": {
2124 "version": "6.1.0",
2125 "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-6.1.0.tgz",
2126 "integrity": "sha512-8L6KtbmreDy4Fc1BdDqaDo9fg0nbedUmTSFQxYPV0uHIM2BBAX8+E0LyMDKgkk0I+mlKto80WYzOnIhT8VDdOg==",
2127 "license": "Apache-2.0",
2128 "dependencies": {
2129 "bare-env": "^3.0.0",
20812130 "bare-events": "^2.5.4",
2082 "bare-stream": "^2.6.4"
2131 "bare-os": "^3.0.1",
2132 "bare-pipe": "^4.2.0",
2133 "bare-structured-clone": "^1.5.2",
2134 "bare-tcp": "^2.4.1",
2135 "bare-url": "^2.2.2"
20832136 },
20842137 "engines": {
2085 "bare": ">=1.16.0"
2138 "bare": ">=1.7.0"
20862139 },
20872140 "peerDependencies": {
2088 "bare-pipe": "*"
2141 "bare-buffer": "*"
20892142 },
20902143 "peerDependenciesMeta": {
2091 "bare-pipe": {
2144 "bare-buffer": {
20922145 "optional": true
20932146 }
20942147 }
20952148 },
2096 "node_modules/bare-semver": {
2097 "version": "1.0.3",
2098 "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.3.tgz",
2099 "integrity": "sha512-HS/A30bi2+PiRJfU6R4+Kp+6KeLSCSByjYM2iiobOKzLAvtu1CT+S8xWfiU7wz0erknjkUoC+yXy108tzIuP5Q==",
2100 "license": "Apache-2.0"
2101 },
21022149 "node_modules/bare-signals": {
21032150 "version": "4.2.0",
21042151 "resolved": "https://registry.npmjs.org/bare-signals/-/bare-signals-4.2.0.tgz",
……@@ -2124,11 +2171,12 @@
21242171 }
21252172 },
21262173 "node_modules/bare-stream": {
2127 "version": "2.13.0",
2128 "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.0.tgz",
2129 "integrity": "sha512-3zAJRZMDFGjdn+RVnNpF9kuELw+0Fl3lpndM4NcEOhb9zwtSo/deETfuIwMSE5BXanA0FrN1qVjffGwAg2Y7EA==",
2174 "version": "2.13.3",
2175 "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.3.tgz",
2176 "integrity": "sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ==",
21302177 "license": "Apache-2.0",
21312178 "dependencies": {
2179 "b4a": "^1.8.1",
21322180 "streamx": "^2.25.0",
21332181 "teex": "^1.0.1"
21342182 },
……@@ -2149,13 +2197,25 @@
21492197 }
21502198 }
21512199 },
2200 "node_modules/bare-stream/node_modules/b4a": {
2201 "version": "1.8.1",
2202 "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz",
2203 "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==",
2204 "license": "Apache-2.0",
2205 "peerDependencies": {
2206 "react-native-b4a": "*"
2207 },
2208 "peerDependenciesMeta": {
2209 "react-native-b4a": {
2210 "optional": true
2211 }
2212 }
2213 },
21522214 "node_modules/bare-structured-clone": {
21532215 "version": "1.6.0",
21542216 "resolved": "https://registry.npmjs.org/bare-structured-clone/-/bare-structured-clone-1.6.0.tgz",
21552217 "integrity": "sha512-AZjEERyqF7kAuudlmgrweT2KwwWM0LsGG4Gx/bWyFwJrKU7E3wNG8c09z2DIrdw93p3vDtfOX8fyHOcXfy5m+g==",
2156 "dev": true,
21572218 "license": "Apache-2.0",
2158 "peer": true,
21592219 "dependencies": {
21602220 "bare-buffer": "^3.6.0",
21612221 "bare-type": "^1.1.0",
……@@ -2170,9 +2230,7 @@
21702230 "version": "3.3.0",
21712231 "resolved": "https://registry.npmjs.org/compact-encoding/-/compact-encoding-3.3.0.tgz",
21722232 "integrity": "sha512-e64XyzlBvTRJ3iScuU/U2w25Dglkm7fhrRbrGaHIwuTlNnzjRKMaQBCVl7mJRvZg7wI5a9wX1IVTXCuaAANNkw==",
2173 "dev": true,
21742233 "license": "Apache-2.0",
2175 "peer": true,
21762234 "dependencies": {
21772235 "b4a": "^1.3.0"
21782236 }
……@@ -2187,42 +2245,38 @@
21872245 "bare-process": "^4.2.1"
21882246 }
21892247 },
2190 "node_modules/bare-subprocess": {
2191 "version": "5.2.3",
2192 "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-5.2.3.tgz",
2193 "integrity": "sha512-07wwswlV7M3sC9IykbZRZ/jHAkrXFWVLqdBWGv1y0ojCimtRD9hGwxdHmR5FUFmDUZLNsBmTYJNQqgio5+A85Q==",
2248 "node_modules/bare-tcp": {
2249 "version": "2.5.2",
2250 "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.5.2.tgz",
2251 "integrity": "sha512-9SAF0r+p5w3QxsI9BGBqj/0VlNwJGkEj/1AAJi+4Pl0W7ke2JiYmt7GhJss/uaEnY0s4/N/A/Os6Dr+dVfVzyQ==",
21942252 "license": "Apache-2.0",
21952253 "dependencies": {
2196 "bare-env": "^3.0.0",
2254 "bare-dns": "^2.0.4",
21972255 "bare-events": "^2.5.4",
2198 "bare-os": "^3.0.1",
2199 "bare-pipe": "^4.0.0",
2200 "bare-url": "^2.2.2"
2256 "bare-stream": "^2.6.4"
22012257 },
22022258 "engines": {
2203 "bare": ">=1.7.0"
2259 "bare": ">=1.16.0"
22042260 },
22052261 "peerDependencies": {
2206 "bare-buffer": "*"
2262 "bare-pipe": "*"
22072263 },
22082264 "peerDependenciesMeta": {
2209 "bare-buffer": {
2265 "bare-pipe": {
22102266 "optional": true
22112267 }
22122268 }
22132269 },
2214 "node_modules/bare-tcp": {
2215 "version": "2.2.7",
2216 "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.2.7.tgz",
2217 "integrity": "sha512-rjpqNQ2cOCkNo3NeYA/W4GTK3DRkl8sDHO3uos+AEswUjLC8XXMQF8WrJCSjlIowCbS6NUVxKE92X5RGXjyefg==",
2270 "node_modules/bare-thread": {
2271 "version": "1.2.4",
2272 "resolved": "https://registry.npmjs.org/bare-thread/-/bare-thread-1.2.4.tgz",
2273 "integrity": "sha512-MnqMCGVp2JJJNXgwUBC8hw+J4FrTeLkLgfCPPl5tQK6MbtV2Efi6LKK5v819VRY0da+AXlCbgssbAVge31NfRg==",
22182274 "license": "Apache-2.0",
22192275 "dependencies": {
2220 "bare-dns": "^2.0.4",
2221 "bare-events": "^2.5.4",
2222 "bare-stream": "^2.6.4"
2223 },
2224 "engines": {
2225 "bare": ">=1.16.0"
2276 "bare-bundle": "^1.9.0",
2277 "bare-module-resolve": "^1.11.2",
2278 "bare-module-traverse": "^2.0.0",
2279 "bare-url": "^2.4.2"
22262280 }
22272281 },
22282282 "node_modules/bare-tls": {
……@@ -2279,9 +2333,9 @@
22792333 }
22802334 },
22812335 "node_modules/bare-url": {
2282 "version": "2.4.1",
2283 "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.1.tgz",
2284 "integrity": "sha512-fZapLWNB25gS+etK27NV9KgBNXgo2yeYHuj+OyPblQd6GYAE3JVy6aKxszMV5jhGGFwraXQKA5fldvf3lMyEqw==",
2336 "version": "2.4.6",
2337 "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.6.tgz",
2338 "integrity": "sha512-iQxPClE07hETVpbRoX7JXX3v/ZQViCxe/SYCxylRLzdEx1xJAufPptfiOqR8tqiCtmbtMDANKWszzjLu1PMAZQ==",
22852339 "license": "Apache-2.0",
22862340 "dependencies": {
22872341 "bare-path": "^3.0.0"
……@@ -2301,6 +2355,20 @@
23012355 "bare-type": "^1.0.6"
23022356 }
23032357 },
2358 "node_modules/bare-worker": {
2359 "version": "4.4.0",
2360 "resolved": "https://registry.npmjs.org/bare-worker/-/bare-worker-4.4.0.tgz",
2361 "integrity": "sha512-zSc1biis9ks03nj/24M7tYS2V0CPhefizzRIxVYdglbbUAgA0zakwSgTKLJshZ6P+9NA55M/eG4k/rBALZVbxg==",
2362 "license": "Apache-2.0",
2363 "dependencies": {
2364 "bare-broadcast-channel": "^0.2.0",
2365 "bare-channel": "^5.1.5",
2366 "bare-events": "^2.2.1",
2367 "bare-module": "^6.4.0",
2368 "bare-stream": "^2.13.3",
2369 "bare-thread": "^1.2.2"
2370 }
2371 },
23042372 "node_modules/bare-ws": {
23052373 "version": "2.1.0",
23062374 "resolved": "https://registry.npmjs.org/bare-ws/-/bare-ws-2.1.0.tgz",
……@@ -2387,26 +2455,6 @@
23872455 "b4a": "^1.5.0"
23882456 }
23892457 },
2390 "node_modules/blake2b": {
2391 "version": "2.1.4",
2392 "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz",
2393 "integrity": "sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==",
2394 "license": "ISC",
2395 "dependencies": {
2396 "blake2b-wasm": "^2.4.0",
2397 "nanoassert": "^2.0.0"
2398 }
2399 },
2400 "node_modules/blake2b-wasm": {
2401 "version": "2.4.0",
2402 "resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz",
2403 "integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==",
2404 "license": "MIT",
2405 "dependencies": {
2406 "b4a": "^1.0.1",
2407 "nanoassert": "^2.0.0"
2408 }
2409 },
24102458 "node_modules/blind-pairing": {
24112459 "version": "2.3.1",
24122460 "resolved": "https://registry.npmjs.org/blind-pairing/-/blind-pairing-2.3.1.tgz",
……@@ -2504,12 +2552,6 @@
25042552 }
25052553 }
25062554 },
2507 "node_modules/cjs-module-lexer": {
2508 "version": "1.4.3",
2509 "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
2510 "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
2511 "license": "MIT"
2512 },
25132555 "node_modules/cli-box": {
25142556 "version": "6.0.10",
25152557 "resolved": "https://registry.npmjs.org/cli-box/-/cli-box-6.0.10.tgz",
……@@ -2659,6 +2701,23 @@
26592701 "integrity": "sha512-eKuHDVfJVg+u/0nPy8P+fhnLgbyuTgVxuCRrS/R7EpDSMMkBDgSes41MJtSAY1F1hcqfHz3Zy/qpqHHIp/EhdA==",
26602702 "license": "MIT"
26612703 },
2704 "node_modules/debug": {
2705 "version": "4.4.3",
2706 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
2707 "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
2708 "license": "MIT",
2709 "dependencies": {
2710 "ms": "^2.1.3"
2711 },
2712 "engines": {
2713 "node": ">=6.0"
2714 },
2715 "peerDependenciesMeta": {
2716 "supports-color": {
2717 "optional": true
2718 }
2719 }
2720 },
26622721 "node_modules/deffy": {
26632722 "version": "2.2.5",
26642723 "resolved": "https://registry.npmjs.org/deffy/-/deffy-2.2.5.tgz",
……@@ -2739,17 +2798,39 @@
27392798 "node": ">=6"
27402799 }
27412800 },
2742 "node_modules/drive-resolve": {
2743 "version": "1.3.1",
2744 "resolved": "https://registry.npmjs.org/drive-resolve/-/drive-resolve-1.3.1.tgz",
2745 "integrity": "sha512-Fn88wa5vry4JKtE1g4md1SPzU9/fO2h8l73Fr9kmQtaatFIvquR/V6UGjTOcBsWbNgrRMQjY8N6SNoY40o57JQ==",
2746 "license": "Apache-2.0",
2801 "node_modules/electron": {
2802 "version": "43.2.0",
2803 "resolved": "https://registry.npmjs.org/electron/-/electron-43.2.0.tgz",
2804 "integrity": "sha512-80zvrgG7ZRXD+tD0IyLvrnN9n+veSxadMRsMaC9wKKP3iUbtC7rGM8+dVuCmOb0Rrwwv8ESW4awnUZh9Hbp1fA==",
2805 "license": "MIT",
27472806 "dependencies": {
2748 "b4a": "^1.6.4",
2749 "bare-module-resolve": "^1.2.5",
2750 "unix-path-resolve": "^1.0.2"
2807 "@electron-internal/extract-zip": "^1.0.1",
2808 "@electron/get": "^5.0.0",
2809 "@types/node": "^24.9.0"
2810 },
2811 "bin": {
2812 "electron": "cli.js",
2813 "install-electron": "install.js"
2814 },
2815 "engines": {
2816 "node": ">= 22.12.0"
27512817 }
27522818 },
2819 "node_modules/electron/node_modules/@types/node": {
2820 "version": "24.13.3",
2821 "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
2822 "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
2823 "license": "MIT",
2824 "dependencies": {
2825 "undici-types": "~7.18.0"
2826 }
2827 },
2828 "node_modules/electron/node_modules/undici-types": {
2829 "version": "7.18.2",
2830 "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
2831 "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
2832 "license": "MIT"
2833 },
27532834 "node_modules/emoji-regex": {
27542835 "version": "8.0.0",
27552836 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
……@@ -2765,11 +2846,17 @@
27652846 "hyperschema": "^1.19.0"
27662847 }
27672848 },
2768 "node_modules/es-module-lexer": {
2769 "version": "1.7.0",
2770 "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
2771 "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
2772 "license": "MIT"
2849 "node_modules/env-paths": {
2850 "version": "3.0.0",
2851 "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
2852 "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
2853 "license": "MIT",
2854 "engines": {
2855 "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
2856 },
2857 "funding": {
2858 "url": "https://github.com/sponsors/sindresorhus"
2859 }
27732860 },
27742861 "node_modules/escalade": {
27752862 "version": "3.2.0",
……@@ -2919,18 +3006,6 @@
29193006 "which-runtime": "^1.2.0"
29203007 }
29213008 },
2922 "node_modules/fs-native-lock": {
2923 "version": "1.2.0",
2924 "resolved": "https://registry.npmjs.org/fs-native-lock/-/fs-native-lock-1.2.0.tgz",
2925 "integrity": "sha512-x2KlVzvJbNhI2vc+z9+5naq04+6XMyoeLv816sGmP4DWFonu+/N+pigIoDzFV+bdnC5BD3GLeI8eqV/dwCY57Q==",
2926 "license": "Apache-2.0",
2927 "dependencies": {
2928 "bare-fs": "^4.0.1",
2929 "bare-path": "^3.0.0",
2930 "fs-native-extensions": "^1.3.4",
2931 "resource-on-exit": "^1.0.0"
2932 }
2933 },
29343009 "node_modules/function.name": {
29353010 "version": "1.0.14",
29363011 "resolved": "https://registry.npmjs.org/function.name/-/function.name-1.0.14.tgz",
……@@ -2964,11 +3039,11 @@
29643039 "node": "6.* || 8.* || >= 10.*"
29653040 }
29663041 },
2967 "node_modules/get-mime-type": {
2968 "version": "2.0.2",
2969 "resolved": "https://registry.npmjs.org/get-mime-type/-/get-mime-type-2.0.2.tgz",
2970 "integrity": "sha512-pTrc0SYvnFGSri+yjvEIq/m/cg2Ti7Vlrlki13RDicWJzLQgKTCDt8Rhdo80vhEzanOGjbpa+KLYjOiJcA26tQ==",
2971 "license": "Apache-2.0"
3042 "node_modules/graceful-fs": {
3043 "version": "4.2.11",
3044 "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
3045 "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
3046 "license": "ISC"
29723047 },
29733048 "node_modules/graceful-goodbye": {
29743049 "version": "1.3.3",
……@@ -3464,12 +3539,6 @@
34643539 "integrity": "sha512-qaX2mymwUhMq+NQPnx5iR/u2PgqhL6jLzDunMmonOgVofqoFhxzd6kOmiL0DLYZUkN/RvNWYPenoANVn5phlaA==",
34653540 "license": "MIT"
34663541 },
3467 "node_modules/is-valid-variable": {
3468 "version": "1.0.1",
3469 "resolved": "https://registry.npmjs.org/is-valid-variable/-/is-valid-variable-1.0.1.tgz",
3470 "integrity": "sha512-ucsrYzt8kcgu2CAOFFWSfOTwa+vPNzQHK1RL6RooSkwozJ92e9wl4cyG/GLDeuNEVj56kvuNZGCR7eSkzrhudg==",
3471 "license": "MIT"
3472 },
34733542 "node_modules/is-win": {
34743543 "version": "1.0.11",
34753544 "resolved": "https://registry.npmjs.org/is-win/-/is-win-1.0.11.tgz",
……@@ -3520,12 +3589,6 @@
35203589 "b4a": "^1.3.0"
35213590 }
35223591 },
3523 "node_modules/listen-async": {
3524 "version": "1.0.0",
3525 "resolved": "https://registry.npmjs.org/listen-async/-/listen-async-1.0.0.tgz",
3526 "integrity": "sha512-i8x+jPmM3YaeU+5zL+NWMwzPT0/WV0q23rviQuu9EkdPuAYjnnsa5LDL406hJ/QNNkziKpnJ1T+3VxJQELskqw==",
3527 "license": "Apache-2.0"
3528 },
35293592 "node_modules/livefiles": {
35303593 "version": "1.1.0",
35313594 "resolved": "https://registry.npmjs.org/livefiles/-/livefiles-1.1.0.tgz",
……@@ -3544,33 +3607,12 @@
35443607 "integrity": "sha512-Yqi947Vk5Ps2YqhOV8K+RR6bseLhZLIVfovpWJH5cT7GE4Pca8/3iny/3oQ47scD7SfQd3whhxMfc+KgxTgDHA==",
35453608 "license": "MIT"
35463609 },
3547 "node_modules/localdrive": {
3548 "version": "1.12.2",
3549 "resolved": "https://registry.npmjs.org/localdrive/-/localdrive-1.12.2.tgz",
3550 "integrity": "sha512-kISUZK6naLZrvcK/+IqXk5IsAu8S6owlVM0MUT6MZrQSIzLplZ4FXljkEBHwPDe3InVue4FDG9d4p8lKXGgRCQ==",
3551 "license": "Apache-2.0",
3552 "dependencies": {
3553 "b4a": "^1.6.1",
3554 "bare-fs": "^4.0.1",
3555 "bare-path": "^3.0.0",
3556 "mirror-drive": "^1.2.0",
3557 "mutexify": "^1.4.0",
3558 "streamx": "^2.12.5",
3559 "unix-path-resolve": "^1.0.2"
3560 }
3561 },
35623610 "node_modules/lodash.camelcase": {
35633611 "version": "4.3.0",
35643612 "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
35653613 "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
35663614 "license": "MIT"
35673615 },
3568 "node_modules/lodash.sortby": {
3569 "version": "4.7.0",
3570 "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
3571 "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
3572 "license": "MIT"
3573 },
35743616 "node_modules/long": {
35753617 "version": "5.3.2",
35763618 "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
……@@ -3623,6 +3665,23 @@
36233665 "bare-module": "*"
36243666 }
36253667 },
3668 "node_modules/ms": {
3669 "version": "2.1.3",
3670 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
3671 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
3672 "license": "MIT"
3673 },
3674 "node_modules/msix-manager": {
3675 "version": "0.2.5",
3676 "resolved": "https://registry.npmjs.org/msix-manager/-/msix-manager-0.2.5.tgz",
3677 "integrity": "sha512-bfAqCBIIoxCsBCuDCr9wCfucmL0fy8jE4GBf9Yx24ZXDxQe4L7r/CJcNcGQxWx9RdHGCqCuNKrrNLfTYOue3fw==",
3678 "license": "Apache-2.0",
3679 "dependencies": {
3680 "bare-events": "^2.8.2",
3681 "bare-url": "^2.3.2",
3682 "require-addon": "^1.2.0"
3683 }
3684 },
36263685 "node_modules/multicast-dns": {
36273686 "version": "7.2.5",
36283687 "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",
……@@ -4025,215 +4084,66 @@
40254084 "hypercore-id-encoding": "^1.3.0"
40264085 }
40274086 },
4028 "node_modules/pear-api": {
4029 "version": "1.30.0",
4030 "resolved": "https://registry.npmjs.org/pear-api/-/pear-api-1.30.0.tgz",
4031 "integrity": "sha512-b9y4hCBTCmP7m3riC4O+mc5g8KNKJsLjbqi7TOFSZyvuIjJeP/d/caBYXdhKab0rcOz/kkSdNWvedox4zBtERQ==",
4032 "license": "Apache-2.0",
4033 "dependencies": {
4034 "pear-constants": "^1.0.0",
4035 "pear-errors": "^1.0.0",
4036 "pear-gracedown": "^1.0.0",
4037 "pear-gunk": "^1.0.0",
4038 "pear-message": "^1.0.0",
4039 "pear-messages": "^1.0.0",
4040 "pear-pipe": "^1.0.1",
4041 "pear-ref": "^1.0.2",
4042 "pear-run": "^1.0.0",
4043 "pear-updates": "^1.0.1",
4044 "pear-wakeups": "^1.0.0"
4045 }
4046 },
4047 "node_modules/pear-api/node_modules/pear-run": {
4048 "version": "1.0.8",
4049 "resolved": "https://registry.npmjs.org/pear-run/-/pear-run-1.0.8.tgz",
4050 "integrity": "sha512-X56S6WJEvE5UKxH+XI1WhsgN2oCzPMg2jO/FH/bNFWX9a/LQmQobcIuxLPDBH+iuiHPM1inFScrYWVNZGWqWDw==",
4051 "license": "Apache-2.0",
4052 "dependencies": {
4053 "b4a": "^1.6.7",
4054 "bare-path": "^3.0.0",
4055 "bare-subprocess": "^5.1.0",
4056 "paparam": "^1.8.5",
4057 "pear-cmd": "^1.0.0",
4058 "pear-link": "^4.1.0",
4059 "pear-ref": "^1.0.0",
4060 "unix-path-resolve": "^1.0.2",
4061 "url-file-url": "^1.0.5",
4062 "which-runtime": "^1.3.2"
4063 }
4064 },
4065 "node_modules/pear-appdrive": {
4066 "version": "1.1.2",
4067 "resolved": "https://registry.npmjs.org/pear-appdrive/-/pear-appdrive-1.1.2.tgz",
4068 "integrity": "sha512-AmCrZaNGFU/BvHR+oFP/cNEUCH1vbzezsJV9wqASoggyg8d4sSb0L6kr99ugGkAuUFlOBI2uHni71hBTaO2rDA==",
4069 "license": "Apache-2.0",
4070 "dependencies": {
4071 "pear-ipc": "^6.6.1",
4072 "pear-ref": "^1.0.1",
4073 "ready-resource": "^1.1.2"
4074 }
4075 },
4076 "node_modules/pear-bridge": {
4077 "version": "1.2.5",
4078 "resolved": "https://registry.npmjs.org/pear-bridge/-/pear-bridge-1.2.5.tgz",
4079 "integrity": "sha512-n6ILZteZOcESljImP/78Jv35aRNUk6TFMJyNmbVBah7cpV8W0H3IsQEvzTt1d2vCywNN+Tv7RoCVL6V3BAcC9A==",
4080 "license": "Apache-2.0",
4081 "dependencies": {
4082 "bare-http1": "^4.0.2",
4083 "get-mime-type": "^2.0.0",
4084 "listen-async": "^1.0.0",
4085 "pear-appdrive": "^1.0.0",
4086 "pear-errors": "^1.0.0",
4087 "pear-gunk": "^1.0.0",
4088 "pear-stamp": "^1.0.1",
4089 "ready-resource": "^1.1.1",
4090 "script-linker": "^2.5.3",
4091 "sodium-native": "^5.0.9",
4092 "streamx": "^2.21.1"
4093 }
4094 },
4095 "node_modules/pear-cmd": {
4096 "version": "1.0.2",
4097 "resolved": "https://registry.npmjs.org/pear-cmd/-/pear-cmd-1.0.2.tgz",
4098 "integrity": "sha512-vecXkSAFUS0ODh9I2zgsDcC4cW6sTQ1ZZTq5Fj/6G20HprvPNARbvraGJrkv5dRZ8Epezdgjws0vqB4W4VVd6w==",
4099 "license": "Apache-2.0",
4100 "dependencies": {
4101 "paparam": "^1.8.5"
4102 }
4103 },
4104 "node_modules/pear-constants": {
4105 "version": "1.1.3",
4106 "resolved": "https://registry.npmjs.org/pear-constants/-/pear-constants-1.1.3.tgz",
4107 "integrity": "sha512-dW8EkiLXjmzr8C8gUqZEIZ4dEKKljRNBznlRM53JPzkDhd053alCbq+T18sE/D2KvzMBW69/Pp1ExFN07xi1EA==",
4108 "license": "Apache-2.0",
4109 "dependencies": {
4110 "b4a": "^1.6.7",
4111 "blake2b": "^2.1.4",
4112 "pear-aliases": "^1.0.2",
4113 "pear-rti": "^1.0.1",
4114 "sodium-native": "^5.0.6",
4115 "url-file-url": "^1.0.5",
4116 "which-runtime": "^1.3.0"
4117 }
4118 },
4119 "node_modules/pear-crasher": {
4120 "version": "1.0.1",
4121 "resolved": "https://registry.npmjs.org/pear-crasher/-/pear-crasher-1.0.1.tgz",
4122 "integrity": "sha512-Ott6ANdu01t5zUXDQ50g0QRQ57SZu35KLuRjuKRsrOLLwdKeBTNYscX4VCgLnfKINlpGtRz/vzUGFPgBXGf6lg==",
4123 "license": "Apache-2.0",
4124 "dependencies": {
4125 "pear-rti": "^1.0.1"
4126 }
4127 },
4128 "node_modules/pear-electron": {
4129 "version": "1.7.28",
4130 "resolved": "https://registry.npmjs.org/pear-electron/-/pear-electron-1.7.28.tgz",
4131 "integrity": "sha512-ZCOFvVmUZgPxl8bCG0EllweW+eO2svGM5BLFNI8nppXdiIeE7ns8fLsQnGS2JdVALpG7ilaNja5pq1XRHbvhYw==",
4132 "license": "Apache-2.0",
4133 "dependencies": {
4134 "bare-env": "^3.0.0",
4135 "bare-fs": "^4.0.1",
4136 "bare-os": "^3.4.0",
4137 "bare-path": "^3.0.0",
4138 "bare-subprocess": "^5.0.2",
4139 "compact-encoding": "^2.16.1",
4140 "localdrive": "^1.12.1",
4141 "paparam": "^1.6.1",
4142 "pear-api": "^1.29.1",
4143 "pear-cmd": "^1.0.0",
4144 "pear-constants": "^1.0.0",
4145 "pear-crasher": "^1.0.1",
4146 "pear-errors": "^1.0.0",
4147 "pear-gunk": "^1.0.0",
4148 "pear-ipc": "^6.4.0",
4149 "pear-link": "^4.1.0",
4150 "pear-logger": "^1.0.0",
4151 "pear-pipe": "^1.0.2",
4152 "pear-run": "^1.0.0",
4153 "pear-state": "^1.0.2",
4154 "pear-terminal": "^1.0.0",
4155 "pear-tryboot": "^1.0.0",
4156 "script-linker": "^2.5.3",
4157 "streamx": "^2.20.2",
4158 "unix-path-resolve": "^1.0.2",
4159 "url-file-url": "^1.0.4",
4160 "which-runtime": "^1.2.1"
4161 }
4162 },
4163 "node_modules/pear-electron/node_modules/pear-run": {
4164 "version": "1.0.8",
4165 "resolved": "https://registry.npmjs.org/pear-run/-/pear-run-1.0.8.tgz",
4166 "integrity": "sha512-X56S6WJEvE5UKxH+XI1WhsgN2oCzPMg2jO/FH/bNFWX9a/LQmQobcIuxLPDBH+iuiHPM1inFScrYWVNZGWqWDw==",
4167 "license": "Apache-2.0",
4168 "dependencies": {
4169 "b4a": "^1.6.7",
4170 "bare-path": "^3.0.0",
4171 "bare-subprocess": "^5.1.0",
4172 "paparam": "^1.8.5",
4173 "pear-cmd": "^1.0.0",
4174 "pear-link": "^4.1.0",
4175 "pear-ref": "^1.0.0",
4176 "unix-path-resolve": "^1.0.2",
4177 "url-file-url": "^1.0.5",
4178 "which-runtime": "^1.3.2"
4179 }
4180 },
41814087 "node_modules/pear-errors": {
41824088 "version": "1.0.1",
41834089 "resolved": "https://registry.npmjs.org/pear-errors/-/pear-errors-1.0.1.tgz",
41844090 "integrity": "sha512-KQyhym09QpLT4H/z3uLW0bqixgIZic2Eip2Q8Z72QmIpFzPtp6QmnzOUwB3kuHB4dqKNa+FQWHWH0NSK5lJjlw==",
41854091 "license": "Apache-2.0"
41864092 },
4187 "node_modules/pear-gracedown": {
4188 "version": "1.0.3",
4189 "resolved": "https://registry.npmjs.org/pear-gracedown/-/pear-gracedown-1.0.3.tgz",
4190 "integrity": "sha512-PVh4AmpMDFxd+kMiCkuTyJ7NzRPgb0AEE7TR5GCl91x90uzWmFWon4TZMrCVhGtADG26OrQpOI+kL6S/o2w00w==",
4093 "node_modules/pear-runtime": {
4094 "version": "1.3.1",
4095 "resolved": "https://registry.npmjs.org/pear-runtime/-/pear-runtime-1.3.1.tgz",
4096 "integrity": "sha512-IoEr3c52L40BrXkjFnMYbeNbbnjuEF8L2toFIe3IyB0lkrUOBZ/mleBiMV6Mq4YLVmp6fWTMHIefMvT/oU3LXw==",
41914097 "license": "Apache-2.0",
41924098 "dependencies": {
4193 "bare-os": "^3.6.1",
4194 "bare-signals": "^4.0.3",
4195 "safety-catch": "^1.0.2",
4196 "url-file-url": "^1.0.5"
4099 "bare-path": "^3.0.0",
4100 "bare-sidecar": "^0.5.2",
4101 "bare-worker": "^4.4.0",
4102 "corestore": "^7.9.1",
4103 "hyperswarm": "^4.17.0",
4104 "pear-runtime-updater": "^3.0.0",
4105 "ready-resource": "^1.2.0"
41974106 }
41984107 },
4199 "node_modules/pear-gunk": {
4200 "version": "1.0.1",
4201 "resolved": "https://registry.npmjs.org/pear-gunk/-/pear-gunk-1.0.1.tgz",
4202 "integrity": "sha512-xN2aGZxGXY/rpSlq24UHsc/RMX12DLJzCM5XPJriDBn7MHUrHoKmD/SZTLT6RlFeL2z9MheRnrge6oR6eIGUMA==",
4108 "node_modules/pear-runtime-updater": {
4109 "version": "3.2.0",
4110 "resolved": "https://registry.npmjs.org/pear-runtime-updater/-/pear-runtime-updater-3.2.0.tgz",
4111 "integrity": "sha512-KLHefj2y0ehG3lE3iAgGSxSbl51ZIM9Arpzb/BW8LTjOmC3n9ydclMgvjlbuA12efQu4MnUvE7nNQ3leISxwLw==",
42034112 "license": "Apache-2.0",
42044113 "dependencies": {
4205 "crc-universal": "^1.0.4",
4206 "fs-native-extensions": "^1.4.3",
4207 "quickbit-universal": "^2.2.0",
4208 "rocksdb-native": "^3.7.5",
4209 "script-linker": "^2.5.4",
4210 "sodium-native": "^5.0.8",
4211 "udx-native": "^1.18.3"
4114 "bare-fs": "^4.5.3",
4115 "bare-path": "^3.0.0",
4116 "bare-semver": "^1.0.2",
4117 "debounceify": "^1.1.0",
4118 "fs-native-extensions": "^1.4.5",
4119 "hypercore-id-encoding": "^1.3.0",
4120 "hyperdrive": "^13.2.1",
4121 "localdrive": "^2.2.0",
4122 "msix-manager": "^0.2.4",
4123 "pear-link": "^5.0.0",
4124 "ready-resource": "^1.2.0",
4125 "which-runtime": "^1.3.2"
42124126 }
42134127 },
4214 "node_modules/pear-ipc": {
4215 "version": "6.11.0",
4216 "resolved": "https://registry.npmjs.org/pear-ipc/-/pear-ipc-6.11.0.tgz",
4217 "integrity": "sha512-7peANATe7VlhbLfTHx3CpIQO9AiHqPkfHK0Wgw5T0EY9KllO/XTPVNAV49VNJ5o0QASrPdrUy6FOvB46HWJflA==",
4128 "node_modules/pear-runtime-updater/node_modules/localdrive": {
4129 "version": "2.2.1",
4130 "resolved": "https://registry.npmjs.org/localdrive/-/localdrive-2.2.1.tgz",
4131 "integrity": "sha512-r7AMrscOky3zIjzOrbH+90P12WmFdQaIlJ26TXaUJrM3hGQ6lIQkWhy8eQs5xDI5ukEyrXp4962EIgO9DFdm+g==",
42184132 "license": "Apache-2.0",
42194133 "dependencies": {
4134 "b4a": "^1.6.1",
42204135 "bare-fs": "^4.0.1",
4221 "bare-os": "^3.2.0",
42224136 "bare-path": "^3.0.0",
4223 "bare-pipe": "^4.0.5",
4224 "framed-stream": "^1.0.1",
4225 "fs-native-extensions": "^1.2.7",
4226 "fs-native-lock": "^1.1.0",
4227 "ready-resource": "^1.0.3",
4228 "streamx": "^2.16.1",
4229 "tiny-buffer-rpc": "^2.2.0",
4230 "which-runtime": "^1.2.0"
4137 "mirror-drive": "^1.2.0",
4138 "mutexify": "^1.4.0",
4139 "streamx": "^2.12.5",
4140 "unix-path-resolve": "^1.0.2"
42314141 }
42324142 },
4233 "node_modules/pear-link": {
4234 "version": "4.2.1",
4235 "resolved": "https://registry.npmjs.org/pear-link/-/pear-link-4.2.1.tgz",
4236 "integrity": "sha512-Y6xSOY36EkWmaeTYqNVT2iV0xWfzCDCBtPCF898793ADk9Lbzfq7RLJ7PhqHRS+dLI7yTlLtCCfjGR3erQ0FKQ==",
4143 "node_modules/pear-runtime-updater/node_modules/pear-link": {
4144 "version": "5.0.0",
4145 "resolved": "https://registry.npmjs.org/pear-link/-/pear-link-5.0.0.tgz",
4146 "integrity": "sha512-Va2xz1vdm4akNonOXOQLsvsxIcT/SWai2R03l9JA5i7YTZa9F3y9AsxtUNBRNLkC4sA6Bk6+9XIa2FzvuoK/FA==",
42374147 "license": "Apache-2.0",
42384148 "dependencies": {
42394149 "bare-path": "^3.0.0",
……@@ -4242,173 +4152,6 @@
42424152 "pear-errors": "^1.0.0"
42434153 }
42444154 },
4245 "node_modules/pear-logger": {
4246 "version": "1.0.1",
4247 "resolved": "https://registry.npmjs.org/pear-logger/-/pear-logger-1.0.1.tgz",
4248 "integrity": "sha512-DMFcqReoaAoxliOSAgw09RwVmWdwXaEPXG/rZ/aITPAVqZetY06P17ipuywEKECH1N1kt5JZ2hVvJPRE/nUllg==",
4249 "license": "Apache-2.0",
4250 "dependencies": {
4251 "bare-format": "^1.0.1",
4252 "bare-hrtime": "^2.0.11",
4253 "pear-cmd": "^1.0.0",
4254 "which-runtime": "^1.3.0"
4255 }
4256 },
4257 "node_modules/pear-message": {
4258 "version": "1.0.0",
4259 "resolved": "https://registry.npmjs.org/pear-message/-/pear-message-1.0.0.tgz",
4260 "integrity": "sha512-ZBZsaIv4PVS38psP/x32D2xaRKf1qI9FnB0gTsRPY0NChV38qhWsnQDbXOhAYGxkTqjREC0OkDoQAha7z6wo/Q==",
4261 "license": "Apache-2.0",
4262 "dependencies": {
4263 "pear-ref": "^1.0.1",
4264 "sodium-native": "^5.0.6"
4265 }
4266 },
4267 "node_modules/pear-messages": {
4268 "version": "1.0.5",
4269 "resolved": "https://registry.npmjs.org/pear-messages/-/pear-messages-1.0.5.tgz",
4270 "integrity": "sha512-2kCw5lnnFxBZ+d4wz8L+AmKi25M0rwdgPWsMTGLBbmkyKmaPVBQBpG8ZktsFwVPGBSLu9dFtGC79VYYDSaA3Vw==",
4271 "license": "Apache-2.0",
4272 "dependencies": {
4273 "b4a": "^1.6.7",
4274 "pear-ipc": "^6.5.0",
4275 "pear-ref": "^1.0.1",
4276 "sodium-native": "^5.0.6"
4277 }
4278 },
4279 "node_modules/pear-opwait": {
4280 "version": "1.0.0",
4281 "resolved": "https://registry.npmjs.org/pear-opwait/-/pear-opwait-1.0.0.tgz",
4282 "integrity": "sha512-V8h7GWihtc5Cam4e0EDJebuwpTxndSRfVsIPAll1YZgf+QG5XrpwQeF8umvxiDBYJXwtJ9P3pVnbsM4jk7vDuA==",
4283 "license": "Apache-2.0",
4284 "dependencies": {
4285 "pear-errors": "^1.0.0"
4286 }
4287 },
4288 "node_modules/pear-pipe": {
4289 "version": "1.0.6",
4290 "resolved": "https://registry.npmjs.org/pear-pipe/-/pear-pipe-1.0.6.tgz",
4291 "integrity": "sha512-7XApSERIgctSlSjsZ8ATkFXwbkIyCEHG90GQdsc1DG2GkDYxYuGrq4c4H/YEE2jt1oq6VywwE/eNtvrlOEUeHg==",
4292 "license": "Apache-2.0",
4293 "dependencies": {
4294 "bare-fs": "^4.1.6",
4295 "bare-pipe": "^4.0.6",
4296 "streamx": "^2.22.1",
4297 "which-runtime": "^1.3.0"
4298 }
4299 },
4300 "node_modules/pear-ref": {
4301 "version": "1.0.2",
4302 "resolved": "https://registry.npmjs.org/pear-ref/-/pear-ref-1.0.2.tgz",
4303 "integrity": "sha512-IUGGSULYVF6jfdtsHY0XOokMp1v1KI89q8yPhsnqrLFf+Wq8EEOD0capny8gqXyu0eGkIh753X1cFUVL36n7FA==",
4304 "license": "Apache-2.0",
4305 "dependencies": {
4306 "bare-events": "^2.6.1"
4307 }
4308 },
4309 "node_modules/pear-rti": {
4310 "version": "1.0.1",
4311 "resolved": "https://registry.npmjs.org/pear-rti/-/pear-rti-1.0.1.tgz",
4312 "integrity": "sha512-rpVNVY9Zwu8ng5sTywaMV8exCkzRWATVElmCsgFH2zfdvVqvsYMxVN1oW9xKSAP2eKJ8cInoL1UmMJLcdbFIXA==",
4313 "license": "Apache-2.0",
4314 "dependencies": {
4315 "bare-path": "^3.0.0"
4316 }
4317 },
4318 "node_modules/pear-run": {
4319 "version": "2.0.0",
4320 "resolved": "https://registry.npmjs.org/pear-run/-/pear-run-2.0.0.tgz",
4321 "integrity": "sha512-BD+XZkaY7UaIZZ2CKx0lhsliuGUfA+SMgIXHck9tXhP7NVMqkaE5kzYHBtz0A115ap2AjCyfPobCpEtj+5KAiw==",
4322 "license": "Apache-2.0",
4323 "dependencies": {
4324 "b4a": "^1.6.7",
4325 "bare-path": "^3.0.0",
4326 "bare-subprocess": "^5.1.0",
4327 "paparam": "^1.8.5",
4328 "pear-cmd": "^1.0.0",
4329 "pear-errors": "^1.0.1",
4330 "pear-link": "^4.1.0",
4331 "pear-ref": "^1.0.0",
4332 "unix-path-resolve": "^1.0.2",
4333 "url-file-url": "^1.0.5",
4334 "which-runtime": "^1.3.2"
4335 }
4336 },
4337 "node_modules/pear-stamp": {
4338 "version": "1.0.2",
4339 "resolved": "https://registry.npmjs.org/pear-stamp/-/pear-stamp-1.0.2.tgz",
4340 "integrity": "sha512-1cU2EnHlcLsixP9cPZqIWJORxbCKyDCQ6G9JL1d+GFaEqwVmyOCSxHwzxzSdfTccWzpBI4Zs/5r/l0YpbQuvIg==",
4341 "license": "Apache-2.0",
4342 "dependencies": {
4343 "streamx": "^2.22.1"
4344 }
4345 },
4346 "node_modules/pear-state": {
4347 "version": "1.1.0",
4348 "resolved": "https://registry.npmjs.org/pear-state/-/pear-state-1.1.0.tgz",
4349 "integrity": "sha512-zs09OU6hwvx/25OuMVaCRgLQWKGXVIcd0yFWjCqa1yo9SY9u5GMSxix7nWjtGusTYTtBKAJhFo+i53GcXsosfg==",
4350 "license": "Apache-2.0",
4351 "dependencies": {
4352 "bare-env": "^3.0.0",
4353 "bare-fs": "^4.2.0",
4354 "bare-os": "^3.6.1",
4355 "bare-path": "^3.0.0",
4356 "hypercore-crypto": "^3.6.1",
4357 "hypercore-id-encoding": "^1.3.0",
4358 "pear-constants": "^1.0.0",
4359 "pear-link": "^4.1.0",
4360 "which-runtime": "^1.3.0"
4361 }
4362 },
4363 "node_modules/pear-terminal": {
4364 "version": "1.2.1",
4365 "resolved": "https://registry.npmjs.org/pear-terminal/-/pear-terminal-1.2.1.tgz",
4366 "integrity": "sha512-NPdghB3DAHb8F/BQS1YyZiIAzjtwYxwfzhlk6pkZpFGtT6Lizk0oyM97eq0Np+h/gIyny+l7/Z8G6uZkJyYfSw==",
4367 "license": "Apache-2.0",
4368 "dependencies": {
4369 "bare-events": "^2.6.1",
4370 "bare-fs": "^4.2.0",
4371 "bare-readline": "^1.0.9",
4372 "bare-stream": "^2.7.0",
4373 "bare-tty": "^5.0.2",
4374 "hypercore-id-encoding": "^1.3.0",
4375 "pear-constants": "^1.0.0",
4376 "pear-errors": "^1.0.1",
4377 "pear-gracedown": "^1.0.0",
4378 "pear-opwait": "^1.0.0",
4379 "streamx": "^2.22.1",
4380 "tiny-byte-size": "^1.1.0",
4381 "which-runtime": "^1.3.0"
4382 }
4383 },
4384 "node_modules/pear-tryboot": {
4385 "version": "1.0.0",
4386 "resolved": "https://registry.npmjs.org/pear-tryboot/-/pear-tryboot-1.0.0.tgz",
4387 "integrity": "sha512-0zTaj9vAXsXoKjtKhJfDBRDcfNY+1+zXu9Ttks9UgnCH0yNYTffghABjqNEOvwX5xPwLqzvHlxBamV9MckBkRA==",
4388 "license": "Apache-2.0",
4389 "dependencies": {
4390 "bare-daemon": "^1.2.1",
4391 "pear-constants": "^1.0.0"
4392 }
4393 },
4394 "node_modules/pear-updates": {
4395 "version": "1.1.0",
4396 "resolved": "https://registry.npmjs.org/pear-updates/-/pear-updates-1.1.0.tgz",
4397 "integrity": "sha512-cD759YRSDFLqlr7sM44imVtdQTc18hflvV2v4ENtoBoKfrLnn5HWklsbgTYfE82az7G+3qaE1JBCtBih/W5dvg==",
4398 "license": "Apache-2.0",
4399 "dependencies": {
4400 "pear-messages": "^1.0.0"
4401 }
4402 },
4403 "node_modules/pear-wakeups": {
4404 "version": "1.0.0",
4405 "resolved": "https://registry.npmjs.org/pear-wakeups/-/pear-wakeups-1.0.0.tgz",
4406 "integrity": "sha512-by8XW24RjQcgETxwGJYnOAnnyFtMOC6++G/3zdwDDBuxouKZnib3JVWBdGvNdTiI8IpedApCOLqNZaHrkBxyvA==",
4407 "license": "Apache-2.0",
4408 "dependencies": {
4409 "pear-messages": "^1.0.0"
4410 }
4411 },
44124155 "node_modules/pino": {
44134156 "version": "9.14.0",
44144157 "resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz",
……@@ -4503,6 +4246,15 @@
45034246 ],
45044247 "license": "MIT"
45054248 },
4249 "node_modules/progress": {
4250 "version": "2.0.3",
4251 "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
4252 "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
4253 "license": "MIT",
4254 "engines": {
4255 "node": ">=0.4.0"
4256 }
4257 },
45064258 "node_modules/protobufjs": {
45074259 "version": "7.6.4",
45084260 "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.4.tgz",
……@@ -4587,15 +4339,6 @@
45874339 "protomux": "^3.10.1"
45884340 }
45894341 },
4590 "node_modules/punycode": {
4591 "version": "2.3.1",
4592 "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
4593 "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
4594 "license": "MIT",
4595 "engines": {
4596 "node": ">=6"
4597 }
4598 },
45994342 "node_modules/qrcode-terminal": {
46004343 "version": "0.12.0",
46014344 "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz",
……@@ -4784,10 +4527,7 @@
47844527 "version": "1.2.2",
47854528 "resolved": "https://registry.npmjs.org/require-asset/-/require-asset-1.2.2.tgz",
47864529 "integrity": "sha512-uc8nWKhqAxVD9Z4rST2b4yaemrC9Xb5vA1wlCz5AiCYnBYdwGRWNqFjneA5zRILzlo1MNrB63ry9+pc8wNR26w==",
4787 "dev": true,
47884530 "license": "Apache-2.0",
4789 "optional": true,
4790 "peer": true,
47914531 "dependencies": {
47924532 "bare-module-resolve": "^1.6.2"
47934533 },
……@@ -4906,23 +4646,6 @@
49064646 "integrity": "sha512-BpSd8VCuCxW9ZitcdIC/vjs3gMaP9bRBL5nkHcyfX2VrS52n13/rHuBA2xJ/S/4DPuRdAO/Bk8pWd8eD/gHCIA==",
49074647 "license": "Apache-2.0"
49084648 },
4909 "node_modules/script-linker": {
4910 "version": "2.5.4",
4911 "resolved": "https://registry.npmjs.org/script-linker/-/script-linker-2.5.4.tgz",
4912 "integrity": "sha512-hzVNCEyu/1g9egVPk7s+jTgus+ZGd12d/Rjkm2QjOmPW5l07EANXd20cjAjA3aLPRY/n5z1UUESKHUf4tli5Tg==",
4913 "license": "Apache-2.0",
4914 "dependencies": {
4915 "acorn": "^8.6.0",
4916 "b4a": "^1.3.1",
4917 "cjs-module-lexer": "^1.2.2",
4918 "drive-resolve": "^1.0.1",
4919 "es-module-lexer": "^1.6.0",
4920 "is-valid-variable": "^1.0.0",
4921 "read-write-mutexify": "^2.0.0",
4922 "source-map-bare": "^1.0.0",
4923 "unix-path-resolve": "^1.0.2"
4924 }
4925 },
49264649 "node_modules/semver": {
49274650 "version": "7.8.5",
49284651 "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
……@@ -5078,18 +4801,6 @@
50784801 "atomic-sleep": "^1.0.0"
50794802 }
50804803 },
5081 "node_modules/source-map-bare": {
5082 "version": "1.0.0",
5083 "resolved": "https://registry.npmjs.org/source-map-bare/-/source-map-bare-1.0.0.tgz",
5084 "integrity": "sha512-e1AGLUcnbp8l4URDmHXuCRlts4CRwjPVd/2XDD6a3zUdcF5lr7hp2pTYMoklJXaN4CArYBb53jXGVRsSsVsDPA==",
5085 "license": "BSD-3-Clause",
5086 "dependencies": {
5087 "whatwg-url": "^7.0.0"
5088 },
5089 "engines": {
5090 "node": ">= 12"
5091 }
5092 },
50934804 "node_modules/speedometer": {
50944805 "version": "1.1.0",
50954806 "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-1.1.0.tgz",
……@@ -5152,6 +4863,18 @@
51524863 "codecs": "^3.1.0"
51534864 }
51544865 },
4866 "node_modules/sumchecker": {
4867 "version": "3.0.1",
4868 "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
4869 "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
4870 "license": "Apache-2.0",
4871 "dependencies": {
4872 "debug": "^4.1.0"
4873 },
4874 "engines": {
4875 "node": ">= 8.0"
4876 }
4877 },
51554878 "node_modules/tar-stream": {
51564879 "version": "3.2.0",
51574880 "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz",
……@@ -5218,18 +4941,6 @@
52184941 "b4a": "^1.6.0"
52194942 }
52204943 },
5221 "node_modules/tiny-buffer-rpc": {
5222 "version": "2.3.1",
5223 "resolved": "https://registry.npmjs.org/tiny-buffer-rpc/-/tiny-buffer-rpc-2.3.1.tgz",
5224 "integrity": "sha512-oJvKOwEKYAt3IwqX9TOI76DaLKebbWyf3/A723mSw1Vm2qKswV21w0Qc34sSJ1bbBQTmo9IT7ToA7diwz4sgCg==",
5225 "license": "Apache-2.0",
5226 "dependencies": {
5227 "b4a": "^1.6.3",
5228 "compact-encoding": "^2.11.0",
5229 "safety-catch": "^1.0.2",
5230 "streamx": "^2.13.2"
5231 }
5232 },
52334944 "node_modules/tiny-byte-size": {
52344945 "version": "1.1.0",
52354946 "resolved": "https://registry.npmjs.org/tiny-byte-size/-/tiny-byte-size-1.1.0.tgz",
……@@ -5252,15 +4963,6 @@
52524963 "yarn": ">= 1.20.0"
52534964 }
52544965 },
5255 "node_modules/tr46": {
5256 "version": "1.0.1",
5257 "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
5258 "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
5259 "license": "MIT",
5260 "dependencies": {
5261 "punycode": "^2.1.0"
5262 }
5263 },
52644966 "node_modules/typpy": {
52654967 "version": "2.4.0",
52664968 "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.4.0.tgz",
……@@ -5295,6 +4997,16 @@
52954997 "typpy": "^2.3.4"
52964998 }
52974999 },
5000 "node_modules/undici": {
5001 "version": "7.28.0",
5002 "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz",
5003 "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==",
5004 "license": "MIT",
5005 "optional": true,
5006 "engines": {
5007 "node": ">=20.18.1"
5008 }
5009 },
52985010 "node_modules/undici-types": {
52995011 "version": "8.3.0",
53005012 "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
……@@ -5332,39 +5044,12 @@
53325044 "bare-path": "^3.0.0"
53335045 }
53345046 },
5335 "node_modules/url-file-url": {
5336 "version": "1.0.5",
5337 "resolved": "https://registry.npmjs.org/url-file-url/-/url-file-url-1.0.5.tgz",
5338 "integrity": "sha512-RkUWAFWSmCDpyFn2qf2QO8Gnwf0y5RadgJuDpBeFD6gEzDuh6hTNpd/jox4znFFqZ79ghAS0gGM7F3ZU4nrMWw==",
5339 "license": "Apache-2.0",
5340 "dependencies": {
5341 "bare-path": "^3.0.0",
5342 "which-runtime": "^1.2.0"
5343 }
5344 },
53455047 "node_modules/varint": {
53465048 "version": "5.0.0",
53475049 "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz",
53485050 "integrity": "sha512-gC13b/bWrqQoKY2EmROCZ+AR0jitc6DnDGaQ6Ls9QpKmuSgJB1eQ7H3KETtQm7qSdMWMKCmsshyCmUwMLh3OAA==",
53495051 "license": "MIT"
53505052 },
5351 "node_modules/webidl-conversions": {
5352 "version": "4.0.2",
5353 "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
5354 "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
5355 "license": "BSD-2-Clause"
5356 },
5357 "node_modules/whatwg-url": {
5358 "version": "7.1.0",
5359 "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
5360 "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
5361 "license": "MIT",
5362 "dependencies": {
5363 "lodash.sortby": "^4.7.0",
5364 "tr46": "^1.0.1",
5365 "webidl-conversions": "^4.0.2"
5366 }
5367 },
53685053 "node_modules/which-runtime": {
53695054 "version": "1.4.0",
53705055 "resolved": "https://registry.npmjs.org/which-runtime/-/which-runtime-1.4.0.tgz",
package.json +9 -8
……@@ -1,13 +1,16 @@
11{
22 "name": "pearbrowser-desktop",
3 "productName": "PearBrowser",
34 "version": "0.7.1",
4 "description": "P2P browser + decentralized app store + site builder, desktop Pear fork of PearBrowser (jj10133/Vinjari family)",
5 "description": "Local-first P2P browser, catalogue, and publishing platform with an embedded Pear OTA runtime.",
56 "license": "Apache-2.0 AND MIT",
67 "type": "module",
8 "main": "electron/main.cjs",
9 "upgrade": "pear://tco5k7h38uoxatedp1wongdbhjxow1x7jiwm3t1i9cujbebhsbty",
710 "scripts": {
811 "preinstall": "node scripts/check-hiverelay-layout.mjs",
9 "start": "node scripts/native-runtime-required.mjs --dev",
10 "run": "node scripts/native-runtime-required.mjs",
12 "start": "electron electron/main.cjs",
13 "run": "electron electron/main.cjs",
1114 "check:release-evidence": "node scripts/check-release-evidence.mjs",
1215 "check:origin-isolation-smoke-evidence": "node scripts/check-origin-isolation-smoke-evidence.mjs",
1316 "generate:release-evidence-handoff": "node scripts/generate-release-evidence-handoff.mjs",
……@@ -30,7 +33,7 @@
3033 "package:macos-dmg": "node scripts/create-macos-dmg.mjs",
3134 "smoke:qvac:native": "node node_modules/bare/bin/bare qvac-smoke/index.mjs",
3235 "smoke:qvac:browser": "node node_modules/bare/bin/bare qvac-smoke/browser.mjs",
33 "smoke:qvac:pear": "node scripts/native-runtime-required.mjs --smoke qvac-smoke",
36 "smoke:qvac:pear": "npm run smoke:qvac:native",
3437 "smoke:ask-browser:ui": "node qvac-smoke/ask-browser-ui.mjs",
3538 "smoke:ask-browser:native": "node node_modules/bare/bin/bare qvac-smoke/ask-browser.mjs",
3639 "smoke:runtime": "node scripts/runtime-rpc-smoke.mjs",
……@@ -40,7 +43,6 @@
4043 "pear": {
4144 "name": "pearbrowser-desktop",
4245 "type": "desktop",
43 "pre": "pear-electron/pre",
4446 "stage": {
4547 "ignore": [
4648 "/.git",
……@@ -111,9 +113,8 @@
111113 "p2p-hiverelay": "latest",
112114 "p2p-hiverelay-client": "latest",
113115 "p2p-hiverelay-verifier": "latest",
114 "pear-bridge": "1.2.5",
115 "pear-electron": "1.7.28",
116 "pear-run": "2.0.0",
116 "electron": "43.2.0",
117 "pear-runtime": "1.3.1",
117118 "react": "^18.3.1",
118119 "react-dom": "^18.3.1",
119120 "schema-sheets": "^3.1.1"
pear.json +0 -7
……@@ -1,7 +0,0 @@
1{
2 "_comment": "Legacy v2 release identifiers retained only for migration lookup. They are not executable runtime inputs or a v3 publishing workflow.",
3 "links": {
4 "production": "pear://tco5k7h38uoxatedp1wongdbhjxow1x7jiwm3t1i9cujbebhsbty",
5 "provisionTarget": "pear://pdsd1p3m1xsz8aofyndbwux5hqs19h8uswnsrfee5cz8sj9pmj4o"
6 }
7}
previews/next-release-ui.html +11 -11
……@@ -1115,7 +1115,7 @@
11151115 <path d="M12 3 5 6v5c0 5 3 8 7 10 4-2 7-5 7-10V6l-7-3Z"></path>
11161116 <path d="M9 12l2 2 4-5"></path>
11171117 </svg>
1118 <input value="pear://explore" aria-label="Address value" />
1118 <input value="hyper://explore" aria-label="Address value" />
11191119 <span class="route-chip">hybrid</span>
11201120 </label>
11211121
……@@ -1231,7 +1231,7 @@
12311231 <p class="card-copy">Encrypted P2P chat and calls.</p>
12321232 </div>
12331233 </div>
1234 <div class="mono-line">pear://oeeoz3...jzpo</div>
1234 <div class="mono-line">Native v3 package required</div>
12351235 </article>
12361236 <article class="app-card">
12371237 <div class="app-row">
……@@ -1241,7 +1241,7 @@
12411241 <p class="card-copy">Private pay-per-inference chat.</p>
12421242 </div>
12431243 </div>
1244 <div class="mono-line">pear://rpzh3f...b6wo</div>
1244 <div class="mono-line">Native v3 package required</div>
12451245 </article>
12461246 <article class="app-card">
12471247 <div class="app-row">
……@@ -1251,7 +1251,7 @@
12511251 <p class="card-copy">Local-first password manager.</p>
12521252 </div>
12531253 </div>
1254 <div class="mono-line">pear://tywsat...mtzo</div>
1254 <div class="mono-line">Native v3 package required</div>
12551255 </article>
12561256 <article class="app-card">
12571257 <div class="app-row">
……@@ -1261,7 +1261,7 @@
12611261 <p class="card-copy">Community chat over peers.</p>
12621262 </div>
12631263 </div>
1264 <div class="mono-line">pear://wmir47...mouy</div>
1264 <div class="mono-line">Native v3 package required</div>
12651265 </article>
12661266 </div>
12671267 </div>
……@@ -1322,7 +1322,7 @@
13221322 <article class="setting-row">
13231323 <div>
13241324 <div class="row-title">Keet app bundle</div>
1325 <div class="row-sub">pear://oeeoz3w6...zpo</div>
1325 <div class="row-sub">Legacy native record · package required</div>
13261326 </div>
13271327 <span class="badge">app</span>
13281328 </article>
……@@ -1432,11 +1432,11 @@
14321432 const address = document.querySelector('.address input')
14331433 const title = document.querySelector('.browser-tab.active .tab-title')
14341434 const addresses = {
1435 browse: 'pear://explore',
1435 browse: 'hyper://explore',
14361436 apps: 'hyperbee://pearbrowser-network/apps',
1437 sites: 'pear://sites',
1438 library: 'pear://library',
1439 settings: 'pear://settings'
1437 sites: 'hyper://sites',
1438 library: 'hyper://library',
1439 settings: 'hyper://settings'
14401440 }
14411441 const titles = {
14421442 browse: 'PearBrowser Home',
……@@ -1451,7 +1451,7 @@
14511451 const view = button.dataset.view
14521452 buttons.forEach((item) => item.classList.toggle('active', item === button))
14531453 panels.forEach((panel) => panel.classList.toggle('active', panel.dataset.panel === view))
1454 if (address) address.value = addresses[view] || 'pear://explore'
1454 if (address) address.value = addresses[view] || 'hyper://explore'
14551455 if (title) title.textContent = titles[view] || 'PearBrowser'
14561456 })
14571457 })
previews/runtime-shell-ui.html +1 -1
……@@ -83,7 +83,7 @@
8383 <div class="app-info">
8484 <div class="app-name">Keet</div>
8585 <div class="app-desc">End-to-end encrypted P2P chat, voice, and video.</div>
86 <div class="app-meta">pear://oeeoz3... · standalone</div>
86 <div class="app-meta">Legacy native record · verified package required</div>
8787 </div>
8888 <div class="app-actions">
8989 <button class="btn primary">Open</button>
qvac-smoke/index.mjs +5 -5
……@@ -5,7 +5,7 @@ import { createLazyQvacService } from '../backend/ai/qvac-host.mjs'
55
66if (!globalThis.process) globalThis.process = bareProcess
77
8const origin = 'pear://pearbrowser-qvac-native-smoke'
8const origin = 'p2p-local://pearbrowser-qvac-native-smoke'
99const prompt = process.argv.slice(2).join(' ') || 'Reply with exactly: QVAC native smoke passed.'
1010const smokeHome = process.env.QVAC_SMOKE_HOME || path.join(os.tmpdir(), 'pearbrowser-qvac-native-smoke')
1111const localModelPath = process.env.QVAC_SMOKE_MODEL_PATH
……@@ -35,14 +35,14 @@ async function shutdown (code) {
3535 if (shuttingDown) return
3636 shuttingDown = true
3737 try { await service.close() } catch (err) { console.error('[qvac-smoke] cleanup failed:', err?.message || err) }
38 if (globalThis.Pear?.exit) Pear.exit(code)
39 else process.exit(code)
38 process.exit(code)
4039}
4140
42if (globalThis.Pear?.teardown) Pear.teardown(() => shutdown(0))
41process.once('SIGINT', () => { void shutdown(0) })
42process.once('SIGTERM', () => { void shutdown(0) })
4343
4444try {
45 console.log(`[qvac-smoke] runtime=Pear/Bare model=${modelAlias} device=${device}`)
45 console.log(`[qvac-smoke] runtime=Bare worker model=${modelAlias} device=${device}`)
4646 if (localModelPath) console.log(`[qvac-smoke] model-path=${localModelPath}`)
4747 console.log(`[qvac-smoke] storage=${smokeHome}`)
4848 if (!localModelPath) console.log('[qvac-smoke] first run downloads about 386 MB; later runs use QVAC cache')
scripts/check-appling-release.mjs +2 -3
……@@ -3,7 +3,6 @@
33import { existsSync, readFileSync, statSync } from 'node:fs'
44
55const rootPackage = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
6const pearConfig = JSON.parse(readFileSync(new URL('../pear.json', import.meta.url), 'utf8'))
76const applingPackage = JSON.parse(readFileSync(new URL('../appling/package.json', import.meta.url), 'utf8'))
87const applingLock = JSON.parse(readFileSync(new URL('../appling/package-lock.json', import.meta.url), 'utf8'))
98const cmake = readFileSync(new URL('../appling/CMakeLists.txt', import.meta.url), 'utf8')
……@@ -12,7 +11,7 @@ const addPearApplingBlock = cmake.match(/add_pear_appling\([\s\S]*?\n\)/)?.[0] |
1211const errors = []
1312const args = parseArgs(process.argv.slice(2))
1413const expectedVersion = versionFromTag(args.tag) || rootPackage.version
15const productionLink = pearConfig.links?.production || ''
14const productionLink = rootPackage.upgrade || ''
1615const productionId = productionLink.replace(/^pear:\/\//, '')
1716
1817const cmakeId = matchValue(/\bID\s+"([^"]+)"/, 'ID', addPearApplingBlock)
……@@ -25,7 +24,7 @@ if (rootPackage.version !== expectedVersion) {
2524 errors.push(`package.json version ${rootPackage.version} does not match release tag ${args.tag}`)
2625}
2726if (!/^pear:\/\/[a-z0-9]{52}$/i.test(productionLink)) {
28 errors.push(`pear.json links.production is not a pear:// link: ${productionLink || '(missing)'}`)
27 errors.push(`package.json upgrade is not a Pear OTA channel: ${productionLink || '(missing)'}`)
2928}
3029if (cmakeId !== productionId) {
3130 errors.push(`appling CMake ID ${cmakeId || '(missing)'} does not match production key ${productionId || '(missing)'}`)
scripts/generate-native-install-snippet.mjs +0 -9
……@@ -4,7 +4,6 @@ import { execFileSync } from 'node:child_process'
44import { readFileSync } from 'node:fs'
55
66const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
7const pearConfig = JSON.parse(readFileSync(new URL('../pear.json', import.meta.url), 'utf8'))
87
98const SUPPORTED_TARGETS = [
109 { label: 'macOS Apple Silicon', platform: 'macos', arch: 'arm64' },
……@@ -327,7 +326,6 @@ function printInstallGuide (report) {
327326 const windows = report.targets.find((target) => target.platform === 'windows')
328327 const linux = report.targets.find((target) => target.platform === 'linux')
329328 const macosExample = macos[0]
330 const fallback = pearConfig?.links?.production || ''
331329
332330 console.log('# Install Native Packages')
333331 console.log()
……@@ -431,13 +429,6 @@ function printInstallGuide (report) {
431429 console.log(`chmod +x ${linux?.asset?.name || 'PearBrowser-<version>-linux-x64.AppImage'}`)
432430 console.log(`./${linux?.asset?.name || 'PearBrowser-<version>-linux-x64.AppImage'}`)
433431 console.log('```')
434 if (fallback) {
435 console.log()
436 console.log('## Legacy Migration Record')
437 console.log()
438 console.log(`Legacy migration record: \`${fallback}\`.`)
439 console.log('Keep existing data intact while migrating. This record is not a v3 launch or install command; use the native package and app-specific migration guidance.')
440 }
441432}
442433
443434function unique (values) {
scripts/native-runtime-required.mjs +0 -14
……@@ -1,14 +0,0 @@
1#!/usr/bin/env node
2
3// The old source commands started PearBrowser through `pear run`. That command
4// accepted remote project links and hides the boundary a native v3 browser must
5// own. Do not revive it as a fallback. This guard stays explicit until the
6// pinned embedded runtime host, local worker boot/shutdown smoke, and native
7// package build are present in this checkout.
8
9const mode = process.argv.includes('--smoke') ? 'smoke' : process.argv.includes('--dev') ? 'development' : 'run'
10
11console.error(`PearBrowser v3 ${mode} host is not configured in this source checkout.`)
12console.error('Use a verified native package, or complete the embedded pear-runtime host migration first.')
13console.error('A remote pear:// record must never be passed to PearRuntime.run().')
14process.exitCode = 1
scripts/verify-live-catalog.js +1 -2
……@@ -22,7 +22,6 @@ import { readCatalogBee } from './lib/catalog-bee.js'
2222
2323const DEFAULT_KEY = 'f5fb7500bccd60a976d2b1d24246108f4444a210b9ca591533114dffc089934d'
2424const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
25const pearConfig = JSON.parse(readFileSync(new URL('../pear.json', import.meta.url), 'utf8'))
2625const catalogSource = JSON.parse(readFileSync(new URL('../catalog-source/pearbrowser-network.catalog.json', import.meta.url), 'utf8'))
2726const browserSource = catalogSource.apps.find((app) => app.id === 'pearbrowser-desktop')
2827if (!browserSource) throw new Error('catalogue source is missing pearbrowser-desktop')
……@@ -37,7 +36,7 @@ function parseArgs (argv) {
3736 expectCount: 14,
3837 expectName: 'PearBrowser Network',
3938 expectBrowserVersion: pkg.version,
40 expectBrowserLink: pearConfig.links.production,
39 expectBrowserLink: pkg.upgrade,
4140 expectBrowserHomepage: browserSource.homepage
4241 }
4342 for (let i = 0; i < argv.length; i++) {
scripts/verify-pin.js +1 -1
……@@ -45,7 +45,7 @@ const BLOB_SAMPLE_TIMEOUT_MS = 20_000
4545const BLOB_LIST_TIMEOUT_MS = 20_000
4646const HIVERELAY_TIMEOUT_MS = 45_000
4747const HIVERELAY_PROOF_TIMEOUT_MS = 30_000
48const DEFAULT_SAMPLE_PATHS = ['/index.html', '/package.json', '/pear.json']
48const DEFAULT_SAMPLE_PATHS = ['/index.html', '/package.json', '/electron/main.cjs']
4949
5050function parseArgs (argv) {
5151 const args = {
test/catalog-bee.test.js +6 -5
……@@ -14,7 +14,7 @@ const SAMPLE = {
1414 name: ' Pear Picks ',
1515 version: 1,
1616 apps: [
17 { id: 'keet', name: 'Keet', type: 'standalone', description: 'P2P chat', link: 'pear://keetkey', categories: ['chat'], author: 'Holepunch', homepage: 'https://keet.io', source: 'https://github.com/holepunchto/keet', license: 'Apache-2.0' },
17 { id: 'keet', name: 'Keet', type: 'standalone', description: 'P2P chat', link: 'hyper://' + 'b'.repeat(64) + '/', categories: ['chat'], author: 'Holepunch', homepage: 'https://keet.io', source: 'https://github.com/holepunchto/keet', license: 'Apache-2.0' },
1818 { id: 'pearpass', name: 'PearPass', driveKey: 'a'.repeat(64), version: '2.0' }
1919 ]
2020}
……@@ -38,7 +38,7 @@ test('normalizeManifest rejects bad input', () => {
3838 assert.throws(() => normalizeManifest({}), /apps must be an array/)
3939 assert.throws(() => normalizeManifest({ apps: 'nope' }), /apps must be an array/)
4040 assert.throws(() => normalizeManifest({ apps: [{}] }), /needs an id/)
41 assert.throws(() => normalizeManifest({ apps: [{ id: 'x', link: 'pear://one' }, { id: 'x', link: 'pear://two' }] }), /duplicate app id/)
41 assert.throws(() => normalizeManifest({ apps: [{ id: 'x', link: 'hyper://' + 'c'.repeat(64) + '/' }, { id: 'x', link: 'hyper://' + 'd'.repeat(64) + '/' }] }), /duplicate app id/)
4242})
4343
4444test('normalizeManifest allows an explicitly empty community catalog', () => {
……@@ -48,8 +48,9 @@ test('normalizeManifest allows an explicitly empty community catalog', () => {
4848})
4949
5050test('derives an id from driveKey/link when id is absent', () => {
51 const n = normalizeManifest({ apps: [{ link: 'pear://only-a-link' }] })
52 assert.equal(n.apps[0].id, 'pear://only-a-link')
51 const link = 'hyper://' + 'e'.repeat(64) + '/'
52 const n = normalizeManifest({ apps: [{ link }] })
53 assert.equal(n.apps[0].id, 'e'.repeat(64))
5354})
5455
5556test('round-trips through a real Hyperbee using the loader query', async () => {
……@@ -79,7 +80,7 @@ test('round-trips through a real Hyperbee using the loader query', async () => {
7980 const byId = Object.fromEntries(data.apps.map((a) => [a.id, a]))
8081 assert.equal(byId.keet.name, 'Keet')
8182 assert.equal(byId.keet.type, 'standalone')
82 assert.equal(byId.keet.link, 'pear://keetkey')
83 assert.equal(byId.keet.link, 'hyper://' + 'b'.repeat(64) + '/')
8384 assert.equal(byId.keet.source, 'hyperbee')
8485 assert.equal(byId.keet.sourceUrl, 'https://github.com/holepunchto/keet')
8586 assert.equal(byId.keet.homepage, 'https://keet.io')
test/federated-name-resolver.test.js +3 -3
……@@ -40,16 +40,16 @@ test("resolves a trusted contact's claim (owner == contact root)", async () => {
4040 assert.equal(res.candidates, 1)
4141})
4242
43test("resolves a trusted contact's link-only app claim", async () => {
43test("resolves a trusted contact's hyper link claim", async () => {
4444 const root = K('aa')
45 const link = 'pear://contact-app'
45 const link = `hyper://${K('ee')}/contact-app`
4646 const r = stubResolver({
4747 contacts: [{ pubkey: root, displayName: 'Bob', verifiedAt: 1, bindingKey: K('bb') }],
4848 bindings: { [root]: { nameRegKey: K('cc') } },
4949 registries: { [K('cc')]: fakeReg({ app: { target: link, owner: root, version: 1 } }) },
5050 })
5151 const res = await r.resolve('app')
52 assert.equal(res.key, null)
52 assert.equal(res.key, K('ee'))
5353 assert.equal(res.link, link)
5454 assert.equal(res.source, 'Bob')
5555})
test/mobile-source-contract.test.js +11 -8
……@@ -1,9 +1,12 @@
11import test from 'node:test'
22import assert from 'node:assert/strict'
3import { readFileSync } from 'node:fs'
3import { existsSync, readFileSync } from 'node:fs'
4
5const mobileRoot = new URL('../../PearBrowser/', import.meta.url)
6const hasMobileCheckout = existsSync(mobileRoot)
47
58function source (path) {
6 return readFileSync(new URL(`../../PearBrowser/${path}`, import.meta.url), 'utf8')
9 return readFileSync(new URL(path, mobileRoot), 'utf8')
710}
811
912function includesAll (text, fragments) {
……@@ -12,7 +15,7 @@ function includesAll (text, fragments) {
1215 }
1316}
1417
15test('mobile QR scanner accepts supported P2P QR forms and is wired from Home to Browse', () => {
18test('mobile QR scanner accepts supported P2P QR forms and is wired from Home to Browse', { skip: !hasMobileCheckout && 'mobile checkout is not present in this isolated desktop worktree' }, () => {
1619 const qr = source('app/screens/QRScannerScreen.tsx')
1720 const app = source('app/App.tsx')
1821
……@@ -38,7 +41,7 @@ test('mobile QR scanner accepts supported P2P QR forms and is wired from Home to
3841 ])
3942})
4043
41test('mobile Bookmarks, History, and More hub expose local data workflows and status actions', () => {
44test('mobile Bookmarks, History, and More hub expose local data workflows and status actions', { skip: !hasMobileCheckout && 'mobile checkout is not present in this isolated desktop worktree' }, () => {
4245 const bookmarks = source('app/screens/BookmarksScreen.tsx')
4346 const history = source('app/screens/HistoryScreen.tsx')
4447 const more = source('app/screens/MoreScreen.tsx')
……@@ -90,7 +93,7 @@ test('mobile Bookmarks, History, and More hub expose local data workflows and st
9093 ])
9194})
9295
93test('mobile My Sites creates, lists, publishes, previews, shares, and deletes sites', () => {
96test('mobile My Sites creates, lists, publishes, previews, shares, and deletes sites', { skip: !hasMobileCheckout && 'mobile checkout is not present in this isolated desktop worktree' }, () => {
9497 const mySites = source('app/screens/MySitesScreen.tsx')
9598 const app = source('app/App.tsx')
9699
……@@ -114,7 +117,7 @@ test('mobile My Sites creates, lists, publishes, previews, shares, and deletes s
114117 ])
115118})
116119
117test('mobile template picker provides selectable starter templates and opens editor after site creation', () => {
120test('mobile template picker provides selectable starter templates and opens editor after site creation', { skip: !hasMobileCheckout && 'mobile checkout is not present in this isolated desktop worktree' }, () => {
118121 const picker = source('app/screens/TemplatePickerScreen.tsx')
119122 const app = source('app/App.tsx')
120123
……@@ -137,7 +140,7 @@ test('mobile template picker provides selectable starter templates and opens edi
137140 ])
138141})
139142
140test('mobile site editor supports block editing, theme selection, preview, save, publish, and sharing', () => {
143test('mobile site editor supports block editing, theme selection, preview, save, publish, and sharing', { skip: !hasMobileCheckout && 'mobile checkout is not present in this isolated desktop worktree' }, () => {
141144 const editor = source('app/screens/SiteEditorScreen.tsx')
142145 const app = source('app/App.tsx')
143146
……@@ -179,7 +182,7 @@ test('mobile site editor supports block editing, theme selection, preview, save,
179182 ])
180183})
181184
182test('mobile native Explore screens preserve safe catalog targets like React Native Explore', () => {
185test('mobile native Explore screens preserve safe catalog targets like React Native Explore', { skip: !hasMobileCheckout && 'mobile checkout is not present in this isolated desktop worktree' }, () => {
183186 const rn = source('app/screens/ExploreScreen.tsx')
184187 const ios = source('ios-native/PearBrowser/Sources/UI/Screens/ExploreScreen.swift')
185188 const android = source('android-native/app/src/main/java/com/pearbrowser/app/ui/screens/ExploreScreen.kt')
test/name-registry-convergence.test.js +4 -4
……@@ -20,7 +20,7 @@ const hex = (x) => b4a.toString(x, 'hex')
2020const signer = (kp) => (msg) => hex(crypto.sign(b4a.from(msg, 'utf-8'), kp.secretKey))
2121const owner = (kp) => hex(kp.publicKey)
2222const TARGET_A = 'aa'.repeat(32); const TARGET_B = 'bb'.repeat(32); const TARGET_C = 'cc'.repeat(32)
23const PEAR_LINK = 'pear://link-only-app'
23const HYPER_LINK = `hyper://${TARGET_C}/link-only-app`
2424
2525const tmps = []
2626const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
……@@ -129,7 +129,7 @@ test('end-to-end: claim → activeMap → resolveName (the CMD_NAME_RESOLVE path
129129 const R = await new NameRegistry(s.store, { encryptionKey: ENC, namespace: 'nr' }).ready()
130130 try {
131131 await R.claim({ name: 'Alice', target: TARGET_A, owner: owner(ka) }, signer(ka))
132 await R.claim({ name: 'LinkApp', target: PEAR_LINK, owner: owner(ka) }, signer(ka))
132 await R.claim({ name: 'LinkApp', target: HYPER_LINK, owner: owner(ka) }, signer(ka))
133133 const registry = await R.activeMap() // what the backend injects into the resolver
134134 // a typed bare name resolves through the registry tier to a navigable key
135135 const r = resolveName('alice', { petnames: {}, registry })
……@@ -137,8 +137,8 @@ test('end-to-end: claim → activeMap → resolveName (the CMD_NAME_RESOLVE path
137137 assert.equal(r.key, TARGET_A) // → go() builds hyper://<target>/
138138 const link = resolveName('linkapp', { petnames: {}, registry })
139139 assert.equal(link.provenance, 'registry')
140 assert.equal(link.key, null)
141 assert.equal(link.link, PEAR_LINK)
140 assert.equal(link.key, TARGET_C)
141 assert.equal(link.link, HYPER_LINK)
142142 // a petname still wins over the registry (tier order preserved end-to-end)
143143 const pet = resolveName('alice', { petnames: { alice: { key: TARGET_B } }, registry })
144144 assert.equal(pet.provenance, 'petname')
test/name-wire.test.js +15 -7
……@@ -46,12 +46,19 @@ async function withStore (fn) {
4646 }
4747}
4848
49test('curated floor answers a bare name offline (Tier 3)', async () => {
49test('legacy native curated names do not resolve to executable targets', async () => {
5050 await withStore(async (names) => {
5151 const r = await resolveThroughStore(names, 'keet')
52 assert.equal(r.provenance, 'curated')
53 assert.equal(r.link, lookupAlias('keet').link) // the curated bootstrap target
54 assert.equal(r.name, 'keet')
52 assert.equal(lookupAlias('keet')?.link, undefined)
53 assert.deepEqual(r, {
54 name: 'keet',
55 key: null,
56 link: null,
57 legacyMigrationId: lookupAlias('keet').legacyMigrationId,
58 target: null,
59 label: 'Keet',
60 provenance: 'curated'
61 })
5562 })
5663})
5764
……@@ -82,12 +89,13 @@ test('an unknown word resolves to null (URL bar falls through to plain handling)
8289 })
8390})
8491
85test('a petname pointing at a link (not a key) is returned with its link', async () => {
92test('a petname pointing at a browsable Hyper link is returned with its link', async () => {
8693 await withStore(async (names) => {
87 await names.setPetname({ name: 'home', link: 'pear://example/' })
94 const link = `hyper://${PET_KEY}/home`
95 await names.setPetname({ name: 'home', link })
8896 const r = await resolveThroughStore(names, 'home')
8997 assert.equal(r.provenance, 'petname')
90 assert.equal(r.link, 'pear://example/')
98 assert.equal(r.link, link)
9199 assert.equal(r.key, null)
92100 })
93101})
test/pear-v3-host-contract.test.js +33 -0
……@@ -0,0 +1,33 @@
1import test from 'node:test'
2import assert from 'node:assert/strict'
3import { readFileSync } from 'node:fs'
4
5const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
6const worker = readFileSync(new URL('../workers/main.js', import.meta.url), 'utf8')
7const host = readFileSync(new URL('../electron/main.cjs', import.meta.url), 'utf8')
8const preload = readFileSync(new URL('../electron/preload.cjs', import.meta.url), 'utf8')
9const backendEntry = readFileSync(new URL('../index.js', import.meta.url), 'utf8')
10const boot = readFileSync(new URL('../ui/boot.js', import.meta.url), 'utf8')
11
12test('PearBrowser v3 uses an embedded Pear OTA worker behind a native Electron host', () => {
13 assert.equal(pkg.main, 'electron/main.cjs')
14 assert.equal(pkg.scripts.start, 'electron electron/main.cjs')
15 assert.equal(pkg.dependencies?.['pear-runtime'], '1.3.1')
16 assert.equal(pkg.dependencies?.electron, '43.2.0')
17 assert.match(pkg.upgrade, /^pear:\/\/[13-9a-km-uw-z]{52}$/)
18
19 assert.match(host, /new PearRuntime\(/)
20 assert.match(host, /pearRuntime\.run/)
21 assert.match(host, /pearRuntime\.updater\.on\('updated'/)
22 assert.match(host, /pearRuntime\?\.close/)
23 assert.match(host, /crypto\.randomBytes\(32\)/)
24 assert.match(host, /contextIsolation: true/)
25 assert.match(host, /nodeIntegration: false/)
26 assert.match(preload, /contextBridge\.exposeInMainWorld\('pearbrowserRuntime'/)
27 assert.match(worker, /Bare\.argv\[2\]/)
28 assert.match(worker, /PearBrowserRuntime = \{ storagePath, sessionToken \}/)
29 assert.match(backendEntry, /globalThis\.PearBrowserRuntime/)
30 assert.doesNotMatch(backendEntry, /from 'pear-electron'/)
31 assert.doesNotMatch(backendEntry, /Pear\.config/)
32 assert.match(boot, /globalThis\.pearbrowserRuntime\?\.sessionToken/)
33})
test/peercord-catalog.test.js +17 -17
……@@ -6,13 +6,15 @@ import { readFileSync } from 'node:fs'
66const require = createRequire(import.meta.url)
77const { SEED_APPS } = require('../backend/catalogue-seed.js')
88
9const PEERCORD_LINK = 'pear://wmir47w7mai3b1skj66mx7fzso6k6o91kipaney7gtt69npimouy'
9const PEERCORD_MIGRATION_ID = 'wmir47w7mai3b1skj66mx7fzso6k6o91kipaney7gtt69npimouy'
1010
11test('Peercord is seeded as a launchable standalone Pear app', () => {
11test('Peercord is seeded as a migration-required native app, never a remote launcher', () => {
1212 const app = SEED_APPS.find((row) => row.name === 'Peercord')
1313 assert.ok(app, 'Peercord seed row missing')
14 assert.equal(app.link, PEERCORD_LINK)
14 assert.equal(app.link, undefined)
1515 assert.equal(app.type, 'standalone')
16 assert.equal(app.legacyMigrationId, PEERCORD_MIGRATION_ID)
17 assert.equal(app.nativeDeliveryStatus, 'migration-required')
1618 assert.equal(app.driveKey, undefined)
1719 assert.equal(app.author, 'Mastercodeon')
1820 assert.equal(app.version, '1.0.8')
……@@ -22,34 +24,32 @@ test('Peercord is seeded as a launchable standalone Pear app', () => {
2224 assert.ok(app.description.toLowerCase().includes('discord-style'))
2325})
2426
25test('Peercord catalogue source declares window launch mode explicitly', () => {
27test('Peercord catalogue source preserves provenance without an executable target', () => {
2628 const source = JSON.parse(readFileSync(new URL('../catalog-source/pearbrowser-network.catalog.json', import.meta.url), 'utf8'))
2729 const app = source.apps.find((row) => row.id === 'peercord')
2830 assert.ok(app, 'Peercord source row missing')
2931 assert.equal(app.type, 'standalone')
30 assert.equal(app.link, PEERCORD_LINK)
32 assert.equal(app.link, undefined)
33 assert.equal(app.legacyMigrationId, PEERCORD_MIGRATION_ID)
34 assert.equal(app.nativeDelivery?.status, 'migration-required')
3135 assert.equal(app.driveKey, undefined)
3236 assert.equal(app.homepage, 'https://git.churchofmalware.org/mastercodeon/Peercord')
3337 assert.equal(app.source, 'https://git.churchofmalware.org/mastercodeon/Peercord')
3438 assert.equal(app.license, 'GPL-3.0')
3539})
3640
37test('Featured Peercord card uses the window launch path until a headless worker exists', () => {
41test('Featured Peercord card communicates that publisher migration is required', () => {
3842 const shell = readFileSync(new URL('../ui/shell.js', import.meta.url), 'utf8')
3943 const entry = shell.match(/id: 'peercord'[\s\S]*?gradient: 'linear-gradient\([^']+\)'/)
4044 assert.ok(entry, 'Peercord featured entry missing')
41 assert.match(entry[0], /type: 'standalone'/)
42 assert.match(shell, new RegExp(`const PEERCORD_LINK = '${PEERCORD_LINK.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}'`))
43 assert.match(entry[0], /link: PEERCORD_LINK/)
44 assert.match(shell, /catalogue type is/)
45 assert.match(entry[0], /nativeDelivery: \{ status: 'migration-required' \}/)
46 assert.match(entry[0], new RegExp(`legacyMigrationId: '${PEERCORD_MIGRATION_ID}'`))
47 assert.match(shell, /verified native v3 package/)
4548})
4649
47test('Peercord launch shows a first-run standalone trust warning', () => {
50test('Peercord has no legacy standalone launch warning because it is not launchable', () => {
4851 const shell = readFileSync(new URL('../ui/shell.js', import.meta.url), 'utf8')
49 assert.match(shell, /STANDALONE_PRELAUNCH_WARNINGS/)
50 assert.match(shell, /persistent third-party trust prompt/)
51 assert.match(shell, /Approving it executes third-party code and creates a persistent trust decision/)
52 assert.match(shell, /standaloneLaunchWarningsSeen/)
53 assert.match(shell, /pendingStandaloneLaunch/)
54 assert.match(shell, /app\.type === 'hypersite'/)
52 assert.doesNotMatch(shell, /STANDALONE_PRELAUNCH_WARNINGS/)
53 assert.doesNotMatch(shell, /pendingStandaloneLaunch/)
54 assert.match(shell, /nativeDelivery.*migration-required/)
5555})
test/release-packaging.test.js +3 -4
……@@ -20,7 +20,6 @@ import { fileURLToPath, pathToFileURL } from 'node:url'
2020const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
2121const require = createRequire(import.meta.url)
2222const packageLock = JSON.parse(readFileSync(new URL('../package-lock.json', import.meta.url), 'utf8'))
23const pearConfig = JSON.parse(readFileSync(new URL('../pear.json', import.meta.url), 'utf8'))
2423const catalogSource = JSON.parse(readFileSync(new URL('../catalog-source/pearbrowser-network.catalog.json', import.meta.url), 'utf8'))
2524const { SEED_APPS } = require('../backend/catalogue-seed.js')
2625const rootLicense = readFileSync(new URL('../LICENSE', import.meta.url), 'utf8')
……@@ -278,7 +277,7 @@ test('PearBrowser catalogue row is a migration-required native record, not a rem
278277 assert.ok(source, 'catalogue source row missing')
279278 assert.ok(seed, 'offline catalogue seed row missing')
280279 assert.equal(source.version, pkg.version)
281 assert.equal(source.legacyMigrationId, pearConfig.links.production.replace(/^pear:\/\//, ''))
280 assert.equal(source.legacyMigrationId, pkg.upgrade.replace(/^pear:\/\//, ''))
282281 assert.equal(source.nativeDelivery?.status, 'migration-required')
283282 assert.equal(source.driveKey, homepageKey)
284283 assert.equal(source.homepage, `hyper://${homepageKey}/`)
……@@ -726,7 +725,7 @@ test('macOS DMG packager is exposed for public-trust native releases', () => {
726725})
727726
728727test('appling release metadata stays in sync with the production Pear channel', () => {
729 const productionId = pearConfig.links.production.replace(/^pear:\/\//, '')
728 const productionId = pkg.upgrade.replace(/^pear:\/\//, '')
730729 assert.match(applingCmake, new RegExp(`ID "${productionId}"`))
731730 assert.match(applingCmake, new RegExp(`VERSION ${pkg.version.replace(/\./g, '\\.')}`))
732731 assert.equal(applingPkg.name, 'pearbrowser-desktop-appling')
……@@ -1473,7 +1472,7 @@ test('native install snippet generator emits release-note packages for every des
14731472 assert.match(guide.stdout, /\[PearBrowser-0\.5\.0-macos-arm64\.dmg\]\(https:\/\/example\.invalid\/PearBrowser-0\.5\.0-macos-arm64\.dmg\)/)
14741473 assert.match(guide.stdout, /npm run -s generate:native-install-guide/)
14751474 assert.match(guide.stdout, /PowerShell/)
1476 assert.match(guide.stdout, /legacy migration record/i)
1475 assert.doesNotMatch(guide.stdout, /legacy migration record/i)
14771476
14781477 const packageProofDir = join(fixture, 'package-proof')
14791478 mkdirSync(packageProofDir)
test/sheets-catalog-query.test.js +1 -1
……@@ -61,7 +61,7 @@ test('listApps passes a row-scan limit to sheets.list', async () => {
6161test('listApps caps the returned row set at MAX_SHEETS_ROWS', async () => {
6262 const huge = Array.from({ length: MAX_SHEETS_ROWS + 50 }, (_, i) => ({
6363 uuid: 'app-' + i,
64 json: { name: 'App ' + i, type: 'standalone', link: 'pear://' + i }
64 json: { name: 'App ' + i, type: 'standalone', link: 'hyper://' + i.toString(16).padStart(64, '0') + '/' }
6565 }))
6666 const sc = makeCatalog(async () => huge)
6767 const apps = await sc.listApps()
ui/boot.js +4 -4
……@@ -16,7 +16,7 @@ import { RpcClient } from './rpc-client.js'
1616const RPC_PORT_BASE = 9876
1717const RPC_PORT_COUNT = 5
1818const RPC_PROBE_ID = 900000001
19const RPC_SESSION_TOKEN = String(globalThis.Pear?.config?.startId || '')
19const RPC_SESSION_TOKEN = String(globalThis.pearbrowserRuntime?.sessionToken || '')
2020
2121// Must match backend/constants.js exactly (numeric wire codes). This is a
2222// COMPLETE mirror — every command/event the renderer can send or receive.
……@@ -315,7 +315,7 @@ function diagnosticUrlFor (url) {
315315}
316316
317317function rendererUrlFor (port) {
318 if (!RPC_SESSION_TOKEN) throw new Error('Pear runtime RPC session token is unavailable')
318 if (!RPC_SESSION_TOKEN) throw new Error('PearBrowser v3 runtime session token is unavailable')
319319 return `ws://127.0.0.1:${port}/?session=${encodeURIComponent(RPC_SESSION_TOKEN)}`
320320}
321321
……@@ -415,8 +415,8 @@ export async function startBackend () {
415415 // running or crashed before binding the WS server. Since v0.4.4
416416 // the main process catches synchronous boot failures and still
417417 // binds the WS — emitting a `backend-boot-failed` event — so a
418 // pure port-scan failure means the main process itself didn't
419 // start (pear-electron handoff issue, NOT a backend crash).
418 // pure port-scan failure means the native host itself did not start, not
419 // that the backend reported a structured boot failure.
420420 //
421421 // Most common cause: an interrupted local installation. Do not revive a
422422 // remote app reference; reinstall the verified signed native package.
ui/shell.js +7 -10
……@@ -1457,23 +1457,20 @@ function Browse ({ rpc, C, navUrl, onNavigated, tabs, setTabs, activeId, setActi
14571457 ))))
14581458 }
14591459
1460 // Try to open devtools for the active tab's iframe. pear-electron
1461 // exposes Pear.Window.devtools(...) on some channels; fall back to
1462 // a console log if unavailable.
1460 // Ask the native v3 host to open devtools for the active renderer. Fall back
1461 // to a concise status message if the host capability is unavailable.
14631462 const openDevtools = () => {
14641463 try {
14651464 const el = iframeRefs.current[activeId]
14661465 const cw = el?.contentWindow
14671466 if (!cw) return
1468 // Path 1: pear-electron exposes Pear.Window.openDevTools()
1469 if (typeof Pear !== 'undefined' && Pear.Window?.openDevTools) {
1470 Pear.Window.openDevTools({ mode: 'detach' })
1467 // The native v3 host exposes only this focused devtools capability.
1468 if (globalThis.pearbrowserRuntime?.openDevTools) {
1469 globalThis.pearbrowserRuntime.openDevTools()
14711470 return
14721471 }
1473 // Path 2: chrome devtools protocol via remote debugging is not
1474 // exposed by default; surface a hint instead.
1475 console.log('[devtools] runtime does not expose openDevTools — relaunch with --devtools')
1476 updateTab(activeId, { status: 'devtools: relaunch with `pear run --dev --devtools .`' })
1472 console.log('[devtools] native host does not expose openDevTools')
1473 updateTab(activeId, { status: 'devtools are unavailable in this native build' })
14771474 setTimeout(() => updateTab(activeId, { status: '' }), 3000)
14781475 } catch (err) {
14791476 console.error('[devtools] failed:', err)
workers/main.js +15 -0
……@@ -0,0 +1,15 @@
1// PearBrowser's v3 Bare worker. PearRuntime.run() places user-supplied worker
2// arguments after the executable and worker specifier, so the first two live
3// at Bare.argv[2] and Bare.argv[3]. Keep this tiny bootstrap separate from the
4// backend so its launch contract is explicit and testable.
5const args = globalThis.Bare?.argv || []
6const storagePath = String(args[2] || '')
7const sessionToken = String(args[3] || '')
8
9if (!storagePath || !sessionToken) {
10 throw new Error('PearBrowser v3 worker requires storage path and session token')
11}
12
13globalThis.PearBrowserRuntime = { storagePath, sessionToken }
14
15await import('../index.js')