This commit is contained in:
Raven Scott
2026-02-19 16:05:59 -05:00
parent 1246c96d0c
commit 4b42e14d98
17 changed files with 1328 additions and 56 deletions
+37
View File
@@ -0,0 +1,37 @@
# pear-appdrive - Pear Application Drive
## Overview
pear-appdrive provides a read-only, minimal Hyperdrive-compatible class for Pear applications. It allows apps to read their packaged files.
## Installation
```bash
npm install pear-appdrive
```
## Usage
```js
import AppDrive from 'pear-appdrive'
const drive = new AppDrive()
await drive.ready()
const file = await drive.get('/file/from/app')
console.log(file.toString())
await drive.close()
```
## Notes
- Read-only
- Minimal Hyperdrive compatibility
## License
Apache-2.0
---
**Module Type**: Runtime | **Ecosystem Role**: App Filesystem | **Dependencies**: hyperdrive
+26
View File
@@ -0,0 +1,26 @@
# pear-appling - Pear Appling Template
## Overview
pear-appling is a template repository for creating Pear applings. It includes a CMake-based build flow.
## Building
```bash
npm i -g bare-make
npm i
bare-make generate
bare-make build
```
## Notes
- Replace placeholders in `CMakeLists.txt`
- Use with cmake-pear for packaging
## License
Apache-2.0
---
**Module Type**: Template | **Ecosystem Role**: App Scaffold | **Dependencies**: bare-make
+57
View File
@@ -0,0 +1,57 @@
# pear-bridge - Local HTTP Bridge for Pear UI
## Overview
pear-bridge provides a local HTTP bridge for Pear desktop applications, used with Pear UI runtimes like pear-electron. It serves UI assets and routes requests.
## Installation
```bash
npm install pear-bridge
```
## Quick Start
```js
import Runtime from 'pear-electron'
import Bridge from 'pear-bridge'
const runtime = new Runtime()
await runtime.ready()
const server = new Bridge()
await server.ready()
const pipe = runtime.start({ info: server.info() })
Pear.teardown(() => pipe.end())
```
## API Reference
### `new Bridge(opts)`
**Options:**
- `mount` (string): Mount path for lookups
- `waypoint` (string): Catch-all HTML path (relative to mount)
- `bypass` (array): Mount bypass paths (default: ['/node_modules'])
### Methods
- `ready()` - Wait for server to listen
- `close()` - Close server
### Properties
- `closed`, `opened`, `closing`, `opening`
## Best Practices
- Use `waypoint` for SPA routing
- Limit `bypass` to required paths
## License
Apache-2.0
---
**Module Type**: Runtime | **Ecosystem Role**: UI Bridge | **Dependencies**: pear
+196
View File
@@ -0,0 +1,196 @@
# pear-build - Build Appling Artifacts for Pear Apps
## Overview
pear-build builds the app shell (appling) for a Pear application. It wraps `bare-build` in a structured operation stream so callers can observe progress and integrate build status into CLIs or UIs.
### Key Features
- **Opstream output**: Structured progress events (`init`, `build`, `complete`).
- **Appling aware**: Reads `.pear/appling` metadata and builds a platform-specific target.
- **Cross-platform defaults**: Automatically picks the host (`platform-arch`) and icon format.
- **Build pipeline reuse**: Delegates the heavy work to `bare-build`.
- **Pear-friendly**: Uses Pear conventions (appling layout, metadata, entitlements).
### Use Cases
- **CLI build commands**: Emit progress events without bespoke logging.
- **CI packaging**: Build the app shell as part of release artifacts.
- **Developer tooling**: Provide real-time build status in a UI.
- **Custom installers**: Generate appling outputs for bundlers.
## Installation
```bash
npm install pear-build
```
## Quick Start
```js
const build = require('pear-build')
const path = require('bare-path')
const dotPear = path.join(process.cwd(), '.pear')
const stream = build({ dotPear })
stream.on('data', (info) => {
console.log(info.tag, info.data)
})
```
## Architecture
```mermaid
flowchart TD
A[Caller] -->|build({ dotPear })| B[pear-build]
B --> C[pear-opstream]
B --> D[Read .pear/appling/package.json]
B --> E[Resolve host + paths]
B --> F[bare-build]
F --> G[Target artifacts]
C --> H[Progress events]
```
## API Reference
### `const build = require('pear-build')`
Exports a single function.
### `build({ dotPear }) -> Opstream`
Start a build for the appling located under `.pear`.
**Parameters:**
- `dotPear` (string, required): Path to the `.pear` directory.
**Returns:**
- `Opstream`: emits structured progress objects on `data`.
**Event Payloads (via `data`):**
- `{ tag: 'init', data: { dotPear } }`
- `{ tag: 'build', data: { target } }`
- `{ tag: 'complete' }`
**Behavior Notes:**
- Reads `.pear/appling/package.json` and expects `pear.build` metadata.
- Uses `which-runtime` to compute `host` and build target.
- Uses `bare-build` with `standalone: false` and `sign: false`.
## Complete Examples
### Example 1: Build and Print Progress
```js
const build = require('pear-build')
const path = require('bare-path')
const stream = build({ dotPear: path.join(process.cwd(), '.pear') })
stream.on('data', ({ tag, data }) => {
if (tag === 'build') console.log('Target:', data.target)
if (tag === 'complete') console.log('Build finished')
})
```
### Example 2: Integrate with a Logger
```js
const build = require('pear-build')
const path = require('bare-path')
const pino = require('pino')
const log = pino()
const stream = build({ dotPear: path.join(process.cwd(), '.pear') })
stream.on('data', (info) => log.info(info))
```
### Example 3: Surface Errors in a CLI
```js
const build = require('pear-build')
const stream = build({ dotPear: './.pear' })
stream.on('data', (evt) => console.log(evt.tag))
stream.on('error', (err) => {
console.error('Build failed:', err.message)
process.exitCode = 1
})
```
### Example 4: Custom Output Location Awareness
```js
const build = require('pear-build')
const stream = build({ dotPear: '/apps/hello/.pear' })
stream.on('data', (evt) => {
if (evt.tag === 'build') {
console.log('Artifacts in:', evt.data.target)
}
})
```
## Best Practices
- **Validate `.pear` layout** before building; ensure `.pear/appling/package.json` exists.
- **Listen for `error`** on the Opstream in CI to fail fast.
- **Prefer structured logs** by printing `tag` and `data` fields.
- **Run builds on matching host** to avoid unsupported targets.
## Performance Notes
- Build time depends on the size of the appling and native addons.
- Repeated builds are best handled via upstream caching in CI.
## Security Considerations
- Appling builds can execute build hooks; only build trusted app sources.
- If distributing artifacts, verify provenance (signing handled outside pear-build).
## Integration with Other Modules
### With pear-bundle and pear-pack
```js
const build = require('pear-build')
const bundle = require('pear-bundle')
const stream = build({ dotPear: './.pear' })
stream.on('data', async (evt) => {
if (evt.tag === 'complete') {
const packed = await bundle({ cache: true })
console.log('Bundle size:', packed.bundle.byteLength)
}
})
```
### With pear-opstream Consumers
```js
const build = require('pear-build')
const stream = build({ dotPear: './.pear' })
stream.on('data', (evt) => {
// forward to UI progress channel
process.send?.(evt)
})
```
## Error Handling
Common failures include:
- **Missing appling metadata**: `.pear/appling/package.json` missing or invalid.
- **Unsupported platform**: `which-runtime` returns a host not supported by appling.
- **Filesystem errors**: insufficient permissions for `.pear/target`.
Handle these by attaching `error` handlers to the returned stream.
## License
Apache-2.0
---
**Module Type**: Build Tool | **Ecosystem Role**: Pear Packaging | **Dependencies**: bare-build, pear-opstream
+172
View File
@@ -0,0 +1,172 @@
# pear-bundle - IPC Bundle Builder for Pear Apps
## Overview
pear-bundle requests a bundle from the Pear runtime over IPC. It is designed to run inside a Pear environment and returns a tracked reference to the bundle result, including the compiled bundle buffer and prebuilds.
### Key Features
- **Pear-aware**: Requires Pear IPC to be present at runtime.
- **Simple API**: Single `bundle(opts)` entry point.
- **Reference tracking**: Uses `pear-ref` to track the IPC resource lifecycle.
- **Consistent options**: Accepts options compatible with `pear-pack` (plus caching).
### Use Cases
- **In-app bundling**: Generate bundles from within a Pear app.
- **CLI tooling**: Delegate bundle creation to the Pear runtime.
- **Caching**: Reuse cached bundles for faster rebuilds.
- **Packaging pipelines**: Connect IPC bundles to release steps.
## Installation
```bash
npm install pear-bundle
```
## Quick Start
```js
const bundle = require('pear-bundle')
const packed = await bundle({ cache: true, entry: '/boot.js' })
console.log('Bundle bytes:', packed.bundle.byteLength)
```
## Architecture
```mermaid
flowchart LR
A[App code] --> B[pear-bundle]
B --> C[global.Pear IPC]
C --> D[Pear runtime]
D --> E[Bundle + prebuilds]
B --> F[pear-ref tracking]
```
## API Reference
### `const bundle = require('pear-bundle')`
Exports a single function.
### `await bundle(opts) -> { bundle, prebuilds, assets? }`
Request a bundle over Pear IPC.
**Parameters:**
- `opts` (object): Options aligned with `pear-pack` (except `target`) plus `cache`.
**Common Options:**
- `entry` (string): Bundle entrypoint (default `/boot.js`).
- `builtins` (string[]): Builtins to include.
- `hosts` (string[]): Host triplets (e.g. `darwin-arm64`).
- `cache` (boolean): Cache bundle on disk instead of rebuilding.
**Returns:**
- Object with `bundle` (Buffer) and `prebuilds` (Map). Some runtimes also return `assets` (Map).
**Throws:**
- Error if IPC is missing: `pear-bundle is designed for Pear - IPC missing`.
## Complete Examples
### Example 1: Basic Bundle
```js
const bundle = require('pear-bundle')
const packed = await bundle({ entry: '/boot.js' })
console.log(packed.prebuilds.size)
```
### Example 2: Enable Caching
```js
const bundle = require('pear-bundle')
const packed = await bundle({ cache: true })
console.log('Bundle cached, size:', packed.bundle.byteLength)
```
### Example 3: Multi-host Build
```js
const bundle = require('pear-bundle')
const packed = await bundle({
hosts: ['darwin-arm64', 'linux-x64'],
entry: '/boot.js'
})
```
### Example 4: Guard for Non-Pear Environments
```js
const bundle = require('pear-bundle')
try {
const packed = await bundle({ entry: '/boot.js' })
console.log('OK', packed.bundle.byteLength)
} catch (err) {
if (/IPC missing/.test(err.message)) {
console.error('Run inside Pear runtime')
} else {
throw err
}
}
```
## Best Practices
- **Use in Pear runtime only**; check `global.Pear` if needed.
- **Cache in CI** to speed up repeated builds.
- **Pin hosts** when building for release to avoid accidental host mismatch.
- **Persist bundles** after building to avoid IPC re-runs.
## Performance Notes
- IPC call overhead is small compared to bundle generation.
- Caching can reduce builds from seconds to milliseconds.
## Security Considerations
- IPC implies trust in the local Pear runtime; avoid untrusted IPC endpoints.
- Validate bundle provenance before distribution.
## Integration with Other Modules
### With pear-pack
If you need to bundle outside Pear, use `pear-pack` with a drive:
```js
const pack = require('pear-pack')
// pack(drive, opts) for offline or custom bundling
```
### With pear-build
```js
const build = require('pear-build')
const bundle = require('pear-bundle')
const stream = build({ dotPear: './.pear' })
stream.on('data', async (evt) => {
if (evt.tag === 'complete') await bundle({ cache: true })
})
```
## Error Handling
- **IPC missing**: Ensure the code runs in Pear runtime.
- **Bundle errors**: Underlying runtime might reject invalid options or missing entry.
Handle with `try/catch` around `await bundle(...)` and surface useful diagnostics.
## License
Apache-2.0
---
**Module Type**: Runtime Helper | **Ecosystem Role**: Pear Packaging | **Dependencies**: pear-ref
+177
View File
@@ -0,0 +1,177 @@
# pear-cmd - Pear Command Parser and Definitions
## Overview
pear-cmd provides the command parser and command definitions for the Pear CLI. It builds on `paparam` to parse arguments, expose common flags, and ship reusable definitions for the top-level `pear` command and `pear run` subcommand.
### Key Features
- **Unified parsing**: Single entry point for Pear CLI argument parsing.
- **Reusable definitions**: Exposes `pear` and `run` command definitions.
- **Paparam-based**: Lean declarative argument and flag specification.
- **Hidden flags**: Includes advanced and legacy flags for compatibility.
### Use Cases
- **CLI implementation**: Parse args for `pear` commands.
- **Embedding**: Reuse definitions in custom wrappers or tooling.
- **Validation**: Standardize error messages and usage output.
## Installation
```bash
npm install pear-cmd
```
## Quick Start
```js
const cmd = require('pear-cmd')
const parsed = cmd(process.argv.slice(2))
console.log(parsed)
```
## Architecture
```mermaid
flowchart TD
A[argv array] --> B[pear-cmd]
B --> C[paparam command builder]
C --> D[pear definitions]
C --> E[run definitions]
C --> F[parsed command object]
```
## API Reference
### `const cmd = require('pear-cmd')`
Returns a function that parses argv arrays.
### `cmd(argv) -> paparam.command`
Parse an argv array using Pear's command definition.
**Parameters:**
- `argv` (string[]): Argument list (e.g. `process.argv.slice(2)`).
**Returns:**
- `paparam.command`: Parsed command result with flags, args, and rest.
### `require('pear-cmd/pear')`
Returns the definition for the top-level `pear` command (flags only).
### `require('pear-cmd/run')`
Returns the definition for `pear run` command arguments and flags.
## Command Definitions
### Top-level `pear` flags (selected)
- `-v`: Print version.
- `--log`, `--log-labels`, `--log-level`, `--log-fields`, `--log-verbose`.
- `--sidecar`: Raw boot sidecar mode.
- Hidden flags for legacy compatibility: `--run`, `--sandbox`, `--appling`.
### `pear run` flags (selected)
- `<link|dir>`: Link, alias, or directory.
- `--dev`, `--devtools`, `--updates-diff`, `--no-updates`.
- `--link <url>`: Simulate deep-link open.
- `--store <path>`, `--tmp-store`.
- `--unsafe-clear-app-storage`, `--unsafe-clear-preferences`.
- `--checkout <n|release|latest>`, `--detached`, `--preflight`.
## Complete Examples
### Example 1: Parse Top-level Flags
```js
const cmd = require('pear-cmd')
const parsed = cmd(['--log', '--log-level', '2'])
console.log(parsed.flags.log)
console.log(parsed.flags['log-level'])
```
### Example 2: Reuse `pear run` Definition
```js
const { command, arg, rest } = require('paparam')
const runDef = require('pear-cmd/run')
const parser = command('run', ...runDef, arg('[cmd]'), rest('rest'))
const res = parser.parse(['pear://key/app', '--devtools'])
console.log(res.args[0])
```
### Example 3: Show Usage for Invalid Args
```js
const cmd = require('pear-cmd')
try {
cmd(['--unknown'])
} catch (err) {
console.error(err.message)
}
```
### Example 4: Build a Wrapper CLI
```js
const cmd = require('pear-cmd')
const parsed = cmd(process.argv.slice(2))
if (parsed.flags.v) {
console.log('v1.2.3')
process.exit(0)
}
```
## Best Practices
- **Use the provided definitions** to stay aligned with official CLI behavior.
- **Pass raw argv arrays**; do not pre-strip flags unless you know the spec.
- **Respect hidden flags** if you support legacy workflows.
## Performance Notes
- Parsing is lightweight and suitable for CLI startup paths.
## Security Considerations
- Treat parsed values as untrusted input until validated.
- Avoid directly executing user-provided paths or links without checks.
## Integration with Other Modules
### With pear-link
```js
const cmd = require('pear-cmd')
const plink = require('pear-link')
const parsed = cmd(['pear://key/app'])
const target = plink.parse(parsed.args[0])
console.log(target.drive.key)
```
### With pear-run
Pear CLI implementations usually pair `pear-cmd` with `pear-run` or similar runner modules for execution.
## Error Handling
- `paparam` throws on invalid flags or missing required args.
- Surface usage messages in CLI output for best UX.
## License
Apache-2.0
---
**Module Type**: CLI Utility | **Ecosystem Role**: Pear CLI Parsing | **Dependencies**: paparam
+28
View File
@@ -0,0 +1,28 @@
# pear-constants - Pear Constants
## Overview
pear-constants provides constant values used across Pear apps and tooling.
## Installation
```bash
npm install pear-constants
```
## Usage
```js
const constants = require('pear-constants')
```
## Notes
- README minimal; inspect source for exported constants
## License
Apache-2.0
---
**Module Type**: Utility | **Ecosystem Role**: Shared Constants | **Dependencies**: None
+33
View File
@@ -0,0 +1,33 @@
# pear-doctor - Pear Diagnostics App
## Overview
pear-doctor is a Pear application used to run diagnostic checks. It includes a companion “Nurse” UI for manual checks.
## Usage
```bash
pear run pear://<app-key>
```
## Development
```bash
git clone https://github.com/holepunchto/pear-doctor
cd pear-doctor
npm install
pear run --dev .
```
## Notes
- Doctor performs platform checks
- Nurse is a browser-based helper UI
- Checklist persisted in localStorage
## License
Apache-2.0
---
**Module Type**: Application | **Ecosystem Role**: Diagnostics | **Dependencies**: pear
+30
View File
@@ -0,0 +1,30 @@
# pear-errors - Pear Core Error Types
## Overview
pear-errors defines core error types used across Pear. It provides standardized errors for consistent handling.
## Installation
```bash
npm install pear-errors
```
## Usage
```js
const errors = require('pear-errors')
throw errors.INVALID_OPERATION('Not allowed')
```
## Notes
- README is minimal; see source for full list
## License
Apache-2.0
---
**Module Type**: Utility | **Ecosystem Role**: Error Types | **Dependencies**: None
+35
View File
@@ -0,0 +1,35 @@
# pear-info - Pear Project Information
## Overview
pear-info streams Pear project information for a given Pear link. It exposes a stream that emits info as data becomes available.
## Installation
```bash
npm install pear-info
```
## Usage
```js
import info from 'pear-info'
const link = 'pear://...'
const stream = info(link, opts)
stream.on('data', (info) => {
console.log(info)
})
```
## Notes
- Runs as a stream and emits incremental info
## License
Apache-2.0
---
**Module Type**: Tooling | **Ecosystem Role**: App Metadata | **Dependencies**: None
+34
View File
@@ -0,0 +1,34 @@
# pear-init - Pear Project Initializer
## Overview
pear-init creates initial Pear project files via an interactive terminal flow. It emits status data as the user responds to prompts.
## Installation
```bash
npm install pear-init
```
## Usage
```js
import init from 'pear-init'
const stream = init(link, opts)
stream.on('data', (info) => {
console.log(info)
})
```
## Notes
- Designed for terminal use only
- Interacts with user via prompt
## License
Apache-2.0
---
**Module Type**: Tooling | **Ecosystem Role**: Project Bootstrap | **Dependencies**: None
+92
View File
@@ -0,0 +1,92 @@
# pear-inspect - Remote Pear Debugging
## Overview
pear-inspect enables remote debugging of Pear apps by bridging HyperDHT and bare-inspector (Chrome DevTools Protocol). It lets you debug apps running on remote devices.
### Key Features
- **Remote inspector**: Debug over HyperDHT
- **Inspector/Session roles**: App side + debugger side
- **CDP compatible**: Use Chrome DevTools Protocol
- **Works with pear://runtime**
## Installation
```bash
npm install pear-inspect
```
## Quick Start
### App (Inspector)
```js
import nodeInspector from 'inspector'
import { Inspector } from 'pear-inspect'
const inspector = new Inspector({ inspector: nodeInspector })
const inspectorKey = await inspector.enable()
console.log(`Inspector key: ${inspectorKey.toString('hex')}`)
```
### Debugger (Session)
```js
import { Session } from 'pear-inspect'
const session = new Session({ inspectorKey })
session.on('info', ({ filename }) => console.log('entry:', filename))
session.on('message', ({ id, result, error }) => console.log(result || error))
session.connect()
session.post({ id: 1, method: 'Runtime.evaluate', params: { expression: '1 + 2' } })
```
## API Reference
### `new Inspector({ inspector, dhtServer, inspectorKey, filename })`
Creates an Inspector for the current process.
### `await inspector.enable()`
Enable inspection. Returns `inspectorKey`.
### `await inspector.disable()`
Disable inspection.
### `new Session({ inspectorKey, publicKey })`
Create a remote inspection session.
### `session.connect()`
Connect to inspector.
### `session.disconnect()`
Disconnect session.
### `session.post({ id, method, params })`
Send CDP method.
### Events
- `info`: `{ filename }`
- `message`: `{ id, result, error }`
## Best Practices
- Use `inspectorKey` for simple setups
- Call `disconnect()` when DevTools closes
## License
Apache-2.0
---
**Module Type**: Debugging | **Ecosystem Role**: Remote Inspector | **Dependencies**: hyperdht, bare-inspector
+23
View File
@@ -0,0 +1,23 @@
# pear-installer - Pear App Installer Helper
## Overview
pear-installer is used by Pear application installers. The README is minimal; this module serves as a helper for installers.
## Installation
```bash
npm install pear-installer
```
## Notes
- Intended for installer tooling
- See source for APIs
## License
Apache-2.0
---
**Module Type**: Tooling | **Ecosystem Role**: Installer Helper | **Dependencies**: None
+182
View File
@@ -0,0 +1,182 @@
# pear-link - Parse and Serialize Pear Links
## Overview
pear-link parses and serializes Pear links (`pear:`) and local file links (`file:`). It supports Pear-specific link formats with optional fork, length, and dhash parts, and integrates alias resolution via `pear-aliases`.
### Key Features
- **Pear URL parsing**: Supports `pear://` URLs with optional metadata.
- **File URL handling**: Parses `file://` and filesystem paths.
- **Alias support**: Resolve and serialize aliases using `pear-aliases`.
- **Normalization**: Normalize links to stable forms for comparison.
### Use Cases
- **CLI parsing**: Accept links or filesystem paths in commands.
- **App routing**: Handle deep links and link normalization.
- **Share links**: Serialize drive keys into Pear links.
- **Validation**: Produce explicit error messages for invalid links.
## Installation
```bash
npm install pear-link
```
## Quick Start
```js
const plink = require('pear-link')
const parsed = plink.parse('pear://myapp/docs')
console.log(parsed.drive.key)
const link = plink.serialize(parsed)
console.log(link)
```
## Architecture
```mermaid
flowchart TD
A[Input link or path] --> B[pear-link]
B --> C[URL parser]
B --> D[pear-aliases]
B --> E[hypercore-id-encoding]
B --> F[Normalized object]
```
## Pear Link Format
```
pear://[<fork>.<length>.]<keyOrAlias>[.<dhash>]<path>[?<search>][#<lochash>]
```
- `fork`: Hypercore fork id
- `length`: Hypercore length
- `keyOrAlias`: z32 or hex key, or alias
- `dhash`: optional discovery hash
## API Reference
### `const plink = require('pear-link')`
Exports a singleton with `parse`, `serialize`, and `normalize`.
### `plink.parse(link) -> { protocol, pathname, search, hash, origin, drive }`
Parse a Pear or file link.
**Parameters:**
- `link` (string): A `pear://` or `file://` link, or a filesystem path.
**Returns:**
- `protocol` (string): `pear:` or `file:`
- `pathname` (string): Path portion
- `search` (string): Query string, including `?`
- `hash` (string): Fragment, including `#`
- `origin` (string): Normalized origin
- `drive` (object): `{ key, length, fork, hash, alias }`
### `plink.serialize(objOrKey) -> string`
Serialize a parsed object or drive key into a Pear link.
**Parameters:**
- Parsed object returned by `parse`, or a key buffer/string.
### `plink.normalize(link) -> string`
Normalize a link by removing trailing separators. `file://` links are normalized with `/` separators, filesystem paths use the platform separator.
## Complete Examples
### Example 1: Parse a Pear Link
```js
const plink = require('pear-link')
const parsed = plink.parse('pear://myapp/docs?mode=help#intro')
console.log(parsed.protocol)
console.log(parsed.drive.alias)
```
### Example 2: Parse a File Path
```js
const plink = require('pear-link')
const parsed = plink.parse('/Users/me/projects/app')
console.log(parsed.protocol) // file:
```
### Example 3: Serialize from a Key
```js
const plink = require('pear-link')
const link = plink.serialize('f1a2b3...')
console.log(link) // pear://<key>
```
### Example 4: Normalize for Comparisons
```js
const plink = require('pear-link')
const a = plink.normalize('pear://myapp/docs/')
const b = plink.normalize('pear://myapp/docs')
console.log(a === b)
```
## Best Practices
- **Normalize links** before comparisons or cache keys.
- **Validate user input** by catching `ERR_INVALID_LINK`.
- **Prefer aliases** for stable, human-readable links when available.
- **Do not assume `file:`**: relative paths are resolved against cwd.
## Performance Notes
- Parsing uses `URL` and `hypercore-id-encoding`; overhead is minimal.
- Alias resolution is map lookups and cheap.
## Security Considerations
- Treat parsed paths as untrusted; sanitize before file access.
- Avoid exposing raw drive keys in logs if they are sensitive.
## Integration with Other Modules
### With pear-cmd
```js
const cmd = require('pear-cmd')
const plink = require('pear-link')
const parsed = cmd(['pear://myapp'])
const target = plink.parse(parsed.args[0])
```
### With hypercore-id-encoding
`pear-link` uses `hypercore-id-encoding` for key normalization and encoding.
## Error Handling
Errors are thrown with `ERR_INVALID_LINK` from `pear-errors` when:
- Missing or invalid protocol
- Invalid hostname parts
- Non-integer fork/length
- Unknown alias
Handle using `try/catch` around `parse` or `serialize`.
## License
Apache-2.0
---
**Module Type**: Utility | **Ecosystem Role**: Link Parsing | **Dependencies**: pear-errors, pear-aliases, hypercore-id-encoding
+183
View File
@@ -0,0 +1,183 @@
# pear-pack - Bundle and Prebuild Generator for Pear
## Overview
pear-pack builds a portable bundle from a drive and extracts prebuilds and assets. It uses `bare-pack-drive` to package the module graph, then rewrites addon paths to hashed prebuild locations and returns a bundle buffer alongside prebuild and asset maps.
### Key Features
- **Drive-based bundling**: Works directly on a drive (e.g. Hyperdrive).
- **Addon hashing**: Rewrites `.node`/`.bare` paths to content-hashed prebuilds.
- **Asset extraction**: Captures asset files referenced in the bundle.
- **Conditional resolution**: Uses module conditions and extensions per target hosts.
- **Mount support**: Optionally rebundles under a mount path.
### Use Cases
- **Offline packaging**: Create bundles without a running Pear runtime.
- **Multi-host releases**: Generate prebuilds for multiple targets.
- **Custom packers**: Integrate with bespoke pipelines or CI.
- **Asset capture**: Extract assets for separate distribution.
## Installation
```bash
npm install pear-pack
```
## Quick Start
```js
const pack = require('pear-pack')
const Hyperdrive = require('hyperdrive')
const drive = new Hyperdrive('./app-drive')
await drive.ready()
const packed = await pack(drive, { entry: '/boot.js' })
console.log(packed.bundle.byteLength)
```
## Architecture
```mermaid
flowchart TD
A[Drive] --> B[bare-pack-drive]
B --> C[Bundle buffer]
C --> D[bare-unpack]
D --> E[Rewrite addon paths]
D --> F[Collect assets]
E --> G[Prebuild map]
F --> H[Assets map]
```
## API Reference
### `const pack = require('pear-pack')`
Exports a single async function.
### `await pack(drive, opts) -> { bundle, prebuilds, assets }`
**Parameters:**
- `drive` (object, required): Drive with `get(key)` (e.g. Hyperdrive).
- `opts` (object, optional): Packaging options.
**Options:**
- `entry` (string): Entry point (default `/boot.js`).
- `hosts` (string[]|string): Target hosts (e.g. `darwin-arm64`).
- `builtins` (string[]): Builtins to include.
- `imports` (string[]): Extra imports to include.
- `mount` (string): Mount prefix for rebundled paths.
- `assetsPrefix` (string): Prefix for asset keys in the assets map.
- `prebuildPrefix` (string): Prefix for rewritten prebuild paths.
- `conditions` (string[]): Module resolution conditions (default `['node', 'bare']`).
- `extensions` (string[]): Addon extensions (default `['.node', '.bare']`).
**Returns:**
- `bundle` (Buffer): Rebundled bundle buffer.
- `prebuilds` (Map): Maps rewritten prebuild path -> addon Buffer.
- `assets` (Map): Maps asset path -> asset Buffer.
## Complete Examples
### Example 1: Bundle a Drive
```js
const pack = require('pear-pack')
const Hyperdrive = require('hyperdrive')
const drive = new Hyperdrive('./app-drive')
await drive.ready()
const { bundle, prebuilds } = await pack(drive, { entry: '/boot.js' })
console.log('Prebuilds:', prebuilds.size)
```
### Example 2: Multi-host Prebuilds
```js
const pack = require('pear-pack')
const packed = await pack(drive, {
hosts: ['darwin-arm64', 'linux-x64'],
entry: '/boot.js'
})
for (const [path, buf] of packed.prebuilds) {
console.log('Prebuild:', path, buf.length)
}
```
### Example 3: Collect Assets with Prefix
```js
const pack = require('pear-pack')
const packed = await pack(drive, {
assetsPrefix: '/assets',
entry: '/boot.js'
})
for (const [path] of packed.assets) {
console.log('Asset:', path)
}
```
### Example 4: Mount Bundles Under a Prefix
```js
const pack = require('pear-pack')
const packed = await pack(drive, {
mount: '/app',
entry: '/boot.js'
})
// Bundle references now under /app
```
## Best Practices
- **Pin `hosts`** to ensure the right prebuilds are captured.
- **Use `assetsPrefix`** for predictable asset locations in release pipelines.
- **Keep extensions list minimal** to avoid bundling unintended artifacts.
- **Verify `entry`** exists in the drive and is a valid JS module.
## Performance Notes
- Bundling walks the full module graph; large apps can take seconds.
- Prebuild hashing uses `sodium-native` and is CPU-bound for large addons.
- Consider caching bundle output between builds if the drive is unchanged.
## Security Considerations
- Treat drive contents as untrusted; validate or sandbox before bundling.
- Addon prebuilds are binary artifacts; ensure they come from trusted sources.
## Integration with Other Modules
### With pear-bundle
Use `pear-bundle` inside Pear runtime when IPC is available. Use `pear-pack` when bundling offline.
### With bare-pack-drive
`pear-pack` delegates to `bare-pack-drive` and `bare-module-traverse` for resolution logic, so settings should align with those modules.
## Error Handling
Common errors:
- **Missing entry**: `drive.get` fails or entry path not found.
- **Invalid addon**: prebuild extraction fails on non-addon binary.
- **Unsupported host**: missing prebuilds for selected hosts.
Wrap `pack()` in `try/catch` and surface the failing path in error logs.
## License
Apache-2.0
---
**Module Type**: Build Tool | **Ecosystem Role**: Pear Packaging | **Dependencies**: bare-pack-drive, bare-unpack, sodium-native