update
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
# pear-aliases - Built-in Pear Link Aliases
|
||||
|
||||
## Overview
|
||||
|
||||
pear-aliases exports a curated set of well-known Pear link aliases and their corresponding Hypercore keys. It also exposes EOL (end-of-line) release lines for selected aliases.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Canonical aliases**: Standard names like `pear`, `keet`, `runtime`.
|
||||
- **Alias resolution**: Maps alias strings to decoded Hypercore keys.
|
||||
- **EOL tracking**: Lists release line keys for deprecated streams.
|
||||
- **Simple surface**: Two exports: `ALIASES` and `EOLS`.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **Link parsing**: Resolve `pear://alias` to a concrete key.
|
||||
- **UI labeling**: Display official app names for known keys.
|
||||
- **Release management**: Identify EOL release lines.
|
||||
- **Validation**: Restrict to recognized aliases in security-sensitive flows.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-aliases
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const { ALIASES } = require('pear-aliases')
|
||||
|
||||
console.log(!!ALIASES.pear)
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[pear-aliases] --> B[hypercore-id-encoding]
|
||||
A --> C[ALIASES map]
|
||||
A --> D[EOLS map]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `const { ALIASES, EOLS } = require('pear-aliases')`
|
||||
|
||||
Exports two objects.
|
||||
|
||||
### `ALIASES`
|
||||
|
||||
Map of alias name -> decoded Hypercore key (Buffer). Known entries include:
|
||||
|
||||
- `pear`
|
||||
- `keet`
|
||||
- `runtime`
|
||||
- `doctor`
|
||||
- `templates`
|
||||
- `electron`
|
||||
- `pass`
|
||||
|
||||
### `EOLS`
|
||||
|
||||
Map of alias name -> array of decoded keys for end-of-line release streams. Current entries include `pear` and `keet`.
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Resolve an Alias
|
||||
|
||||
```js
|
||||
const { ALIASES } = require('pear-aliases')
|
||||
|
||||
const key = ALIASES.pear
|
||||
console.log(key.toString('hex'))
|
||||
```
|
||||
|
||||
### Example 2: Validate Alias Presence
|
||||
|
||||
```js
|
||||
const { ALIASES } = require('pear-aliases')
|
||||
|
||||
function isKnownAlias(name) {
|
||||
return Object.prototype.hasOwnProperty.call(ALIASES, name)
|
||||
}
|
||||
|
||||
console.log(isKnownAlias('keet'))
|
||||
```
|
||||
|
||||
### Example 3: Check for EOL Release Lines
|
||||
|
||||
```js
|
||||
const { EOLS } = require('pear-aliases')
|
||||
|
||||
const eolKeys = EOLS.pear || []
|
||||
console.log('EOL lines:', eolKeys.length)
|
||||
```
|
||||
|
||||
### Example 4: Integrate with pear-link
|
||||
|
||||
```js
|
||||
const plink = require('pear-link')
|
||||
|
||||
const parsed = plink.parse('pear://pear')
|
||||
console.log(parsed.drive.key)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Prefer aliases** for user-facing links when available.
|
||||
- **Treat unknown aliases as errors** in security-sensitive code.
|
||||
- **Cache lookups** locally if you access `ALIASES` often.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Constant-time map lookup; negligible overhead.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Alias mappings are authoritative; verify provenance of the package in production.
|
||||
- Avoid trusting alias names from untrusted input without checking `ALIASES`.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-link
|
||||
|
||||
`pear-link` resolves aliases using `pear-aliases`, so you typically do not need to interact with `ALIASES` directly.
|
||||
|
||||
### With hypercore-id-encoding
|
||||
|
||||
Keys are decoded using `hypercore-id-encoding` for consistency with core ecosystem formats.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- `pear-aliases` itself does not throw.
|
||||
- Consumers should handle missing aliases or empty `EOLS` arrays as normal cases.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Utility | **Ecosystem Role**: Link Aliases | **Dependencies**: hypercore-id-encoding
|
||||
@@ -0,0 +1,147 @@
|
||||
# pear-message - Send Pear App Messages
|
||||
|
||||
## Overview
|
||||
|
||||
pear-message sends object messages between a Pear application's processes/threads. It publishes messages onto Pear's internal message bus, where they can be received via `pear-messages` using object pattern matching.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **IPC-based**: Uses Pear runtime IPC to deliver messages.
|
||||
- **Object payloads**: Send arbitrary JSON-like objects.
|
||||
- **Pattern routing**: Messages can include matching metadata for receivers.
|
||||
- **Reference tracking**: Uses `pear-ref` to track IPC lifetime.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **App event bus**: Broadcast UI or background events.
|
||||
- **Cross-process messaging**: Notify background services or workers.
|
||||
- **Deep-link handling**: Emit events triggered by link actions.
|
||||
- **Telemetry hooks**: Send structured event objects to listeners.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-message
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const message = require('pear-message')
|
||||
|
||||
await message({ type: 'my-app/ready', data: { ok: true } })
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Sender] --> B[pear-message]
|
||||
B --> C[global.Pear IPC]
|
||||
C --> D[Message bus]
|
||||
D --> E[pear-messages subscribers]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `const message = require('pear-message')`
|
||||
|
||||
Exports a single function.
|
||||
|
||||
### `await message(msg) -> any`
|
||||
|
||||
Send a message over Pear IPC.
|
||||
|
||||
**Parameters:**
|
||||
- `msg` (object): Arbitrary message payload. Can include a `to` pattern.
|
||||
|
||||
**Returns:**
|
||||
- Value returned by the IPC call (runtime-dependent); usually a tracked ref.
|
||||
|
||||
**Throws:**
|
||||
- Error if IPC is missing: `pear-message is designed for Pear - IPC missing`.
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Basic Event Message
|
||||
|
||||
```js
|
||||
const message = require('pear-message')
|
||||
|
||||
await message({ type: 'my-app/user-login', userId: '123' })
|
||||
```
|
||||
|
||||
### Example 2: Pattern-Targeted Message
|
||||
|
||||
```js
|
||||
const message = require('pear-message')
|
||||
|
||||
await message({
|
||||
type: 'my-app/cta-click',
|
||||
to: { pattern: ['match', 'against'] }
|
||||
})
|
||||
```
|
||||
|
||||
### Example 3: Guard for Non-Pear Environments
|
||||
|
||||
```js
|
||||
const message = require('pear-message')
|
||||
|
||||
try {
|
||||
await message({ type: 'my-app/ping' })
|
||||
} catch (err) {
|
||||
if (/IPC missing/.test(err.message)) {
|
||||
console.error('pear-message requires Pear runtime')
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 4: Pair with pear-messages
|
||||
|
||||
```js
|
||||
const message = require('pear-message')
|
||||
const messages = require('pear-messages')
|
||||
|
||||
messages({ type: 'my-app/log' }, (msg) => console.log(msg))
|
||||
|
||||
await message({ type: 'my-app/log', data: { value: 1 } })
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Use a `type` field** to make pattern routing clear and stable.
|
||||
- **Keep payloads small** to reduce IPC overhead.
|
||||
- **Handle IPC absence** when running in non-Pear contexts.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Messaging cost is dominated by IPC serialization; keep objects lightweight.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Do not send secrets in messages unless the receiver is trusted.
|
||||
- Validate incoming message data on the receiving side.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-messages
|
||||
|
||||
`pear-messages` is the standard subscriber side for objects sent by `pear-message`.
|
||||
|
||||
### With pear-ref
|
||||
|
||||
`pear-message` uses `pear-ref` to track IPC resource lifetimes automatically.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Missing IPC throws immediately.
|
||||
- Runtime-specific IPC errors will surface as rejected promises.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Runtime Helper | **Ecosystem Role**: App Messaging | **Dependencies**: pear-ref
|
||||
@@ -0,0 +1,149 @@
|
||||
# pear-messages - Receive Pear App Messages
|
||||
|
||||
## Overview
|
||||
|
||||
pear-messages subscribes to Pear's internal message bus and emits object messages matching a provided pattern. It pairs with `pear-message` to enable cross-process or cross-thread messaging inside a Pear app.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Pattern matching**: Match message objects by subset of properties.
|
||||
- **Stream-based**: Returns an `Iambus` subscriber (Readable stream).
|
||||
- **Pear lifecycle aware**: Auto-ends on `Pear.teardown`.
|
||||
- **Listener shortcuts**: Optional listener callback for convenience.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **App event bus**: Subscribe to internal events.
|
||||
- **UI orchestration**: React to background actions.
|
||||
- **System signals**: Listen for Pear platform messages.
|
||||
- **Telemetry**: Collect message-based analytics.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-messages
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const messages = require('pear-messages')
|
||||
|
||||
const stream = messages({ type: 'my-app/ready' })
|
||||
stream.once('data', console.log)
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[pear-message] --> B[IPC bus]
|
||||
B --> C[pear-messages]
|
||||
C --> D[Readable stream]
|
||||
D --> E[App listeners]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `const messages = require('pear-messages')`
|
||||
|
||||
Exports a single function.
|
||||
|
||||
### `messages(pattern[, listener]) -> Readable`
|
||||
|
||||
Subscribe to messages that match `pattern`.
|
||||
|
||||
**Parameters:**
|
||||
- `pattern` (object): Subset of properties to match. Use `{}` or omit for all messages.
|
||||
- `listener` (function, optional): Called for each matching message.
|
||||
|
||||
**Returns:**
|
||||
- `Readable` (Iambus subscriber) emitting matching message objects.
|
||||
|
||||
### `messages(listener)`
|
||||
|
||||
If the first argument is a function, it is treated as the listener and a catch-all pattern is used.
|
||||
|
||||
**Throws:**
|
||||
- Error if IPC is missing: `pear-messages is designed for Pear - IPC missing`.
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Listen with Pattern
|
||||
|
||||
```js
|
||||
const messages = require('pear-messages')
|
||||
|
||||
messages({ type: 'pear/wakeup' }, (msg) => {
|
||||
console.log('wakeup:', msg)
|
||||
})
|
||||
```
|
||||
|
||||
### Example 2: Catch-all Stream
|
||||
|
||||
```js
|
||||
const messages = require('pear-messages')
|
||||
|
||||
for await (const msg of messages()) {
|
||||
console.log('bus:', msg)
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Pair with pear-message
|
||||
|
||||
```js
|
||||
const message = require('pear-message')
|
||||
const messages = require('pear-messages')
|
||||
|
||||
const clicks = messages({ type: 'my-app/cta' })
|
||||
clicks.on('data', (msg) => console.log(msg))
|
||||
|
||||
await message({ type: 'my-app/cta', data: { id: 1 } })
|
||||
```
|
||||
|
||||
### Example 4: Manual Cleanup
|
||||
|
||||
```js
|
||||
const messages = require('pear-messages')
|
||||
|
||||
const stream = messages({ type: 'my-app/once' })
|
||||
stream.once('data', () => stream.end())
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Use explicit `type` strings** to avoid collisions.
|
||||
- **Keep patterns small** for faster matching.
|
||||
- **Detach listeners** on shutdown if you manage stream lifetimes manually.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Pattern matching is lightweight but scales with message volume.
|
||||
- Catch-all patterns can be noisy; filter early for hot paths.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Treat message data as untrusted; validate before using.
|
||||
- Avoid leaking sensitive data into global message streams.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-message
|
||||
|
||||
`pear-message` is the producer side; use it to publish messages that `pear-messages` consumes.
|
||||
|
||||
### With iambus / streamx
|
||||
|
||||
The returned subscriber is a readable stream; it can be piped or consumed via async iteration.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Missing IPC throws immediately.
|
||||
- Stream errors propagate normally via `error` events.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Runtime Helper | **Ecosystem Role**: App Messaging | **Dependencies**: pear-ref, iambus
|
||||
@@ -0,0 +1,171 @@
|
||||
# pear-opstream - Operation Stream Base Class
|
||||
|
||||
## Overview
|
||||
|
||||
pear-opstream provides a readable stream wrapper around an async operation function. It standardizes progress status emission and always ends with a `final` status object. Logical operation errors are emitted as status objects rather than thrown as stream errors.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Structured status events**: Emits `{ tag, data }` objects.
|
||||
- **Guaranteed final**: Always emits exactly one `final` status.
|
||||
- **Logical error reporting**: Emits `tag: 'error'` without necessarily erroring the stream.
|
||||
- **Link normalization**: Normalizes `params.link` via `pear-link`.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **CLI operations**: Stream progress to terminal or JSON output.
|
||||
- **UI progress reporting**: Drive progress UIs with status events.
|
||||
- **Composable pipelines**: Pair with `pear-opwait` for promise semantics.
|
||||
- **Long-running tasks**: Standardize result reporting.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-opstream
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const Opstream = require('pear-opstream')
|
||||
|
||||
const stream = new Opstream(async (params) => {
|
||||
// do work
|
||||
})
|
||||
|
||||
stream.on('data', console.log)
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Opstream] --> B[Async op(params)]
|
||||
B --> C[Status events]
|
||||
C --> D[{ tag: 'error' }]
|
||||
C --> E[{ tag: 'final' }]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `const Opstream = require('pear-opstream')`
|
||||
|
||||
Exports the `Opstream` class.
|
||||
|
||||
### `new Opstream(op, params, done?)`
|
||||
|
||||
Create a new operation stream.
|
||||
|
||||
**Parameters:**
|
||||
- `op` (function): Async function `(params) => Promise<any>` executed once when the stream reads.
|
||||
- `params` (object): Input passed to `op`. If `params.link` exists, it is normalized.
|
||||
- `done` (function, optional): Called after the final chunk is emitted and the stream ends.
|
||||
|
||||
### `instance.final`
|
||||
|
||||
Optional object to merge into the final status payload.
|
||||
|
||||
**Default:** `{}`
|
||||
|
||||
### Emitted Status Objects
|
||||
|
||||
- **Error status** (logical failure):
|
||||
|
||||
```js
|
||||
{
|
||||
tag: 'error',
|
||||
data: { stack, code, message, success: false, info }
|
||||
}
|
||||
```
|
||||
|
||||
- **Final status** (always emitted once):
|
||||
|
||||
```js
|
||||
{
|
||||
tag: 'final',
|
||||
data: { success, ...final }
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Basic Opstream
|
||||
|
||||
```js
|
||||
const Opstream = require('pear-opstream')
|
||||
|
||||
const stream = new Opstream(async () => {
|
||||
// perform work
|
||||
})
|
||||
|
||||
stream.on('data', (status) => console.log(status))
|
||||
```
|
||||
|
||||
### Example 2: Custom Final Payload
|
||||
|
||||
```js
|
||||
const Opstream = require('pear-opstream')
|
||||
|
||||
const stream = new Opstream(async () => {
|
||||
stream.final = { result: 42 }
|
||||
})
|
||||
|
||||
stream.on('data', console.log)
|
||||
```
|
||||
|
||||
### Example 3: Link Normalization
|
||||
|
||||
```js
|
||||
const Opstream = require('pear-opstream')
|
||||
|
||||
const stream = new Opstream(async (params) => {
|
||||
console.log(params.link) // normalized
|
||||
}, { link: 'pear://app/path/' })
|
||||
```
|
||||
|
||||
### Example 4: Pair with pear-opwait
|
||||
|
||||
```js
|
||||
const Opstream = require('pear-opstream')
|
||||
const opwait = require('pear-opwait')
|
||||
|
||||
const stream = new Opstream(async () => {})
|
||||
const result = await opwait(stream, (status) => console.log(status.tag))
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Use `tag` values consistently** (`init`, `progress`, `final`, etc.).
|
||||
- **Set `this.final`** in subclasses before finishing work.
|
||||
- **Use `pear-opwait`** when you need promise-style completion.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Overhead is small; statuses are simple objects pushed to the stream.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Do not include sensitive data in status payloads if logs are untrusted.
|
||||
- Normalize user-provided links to avoid path discrepancies.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-opwait
|
||||
|
||||
`pear-opwait` consumes opstreams and resolves the final payload, surfacing errors as promise rejections.
|
||||
|
||||
### With pear-link
|
||||
|
||||
If `params.link` is provided, it is normalized via `pear-link`.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Operation rejections emit an `error` status and still end with `final`.
|
||||
- Stream-level errors still propagate through `error` events.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Utility | **Ecosystem Role**: Operation Reporting | **Dependencies**: streamx, pear-link
|
||||
@@ -0,0 +1,150 @@
|
||||
# pear-opwait - Await Opstream Completion
|
||||
|
||||
## Overview
|
||||
|
||||
pear-opwait turns an opstream into a promise. It watches `{ tag, data }` status objects, resolves with the `final` payload, and converts logical `error` statuses into rejected promises.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Promise wrapper**: Resolve on `final`, reject on errors.
|
||||
- **Status observer**: Optional async hook for each status event.
|
||||
- **Error translation**: Converts `tag: 'error'` into `ERR_OPERATION_FAILED`.
|
||||
- **Stream-safe**: Destroys the stream on observer errors.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **CLI commands**: Await operations while still logging progress.
|
||||
- **Programmatic API**: Convert stream-based ops into async/await flows.
|
||||
- **Testing**: Assert on final results without manual stream handling.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-opwait
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const opwait = require('pear-opwait')
|
||||
const Opstream = require('pear-opstream')
|
||||
|
||||
const stream = new Opstream(async () => {})
|
||||
const final = await opwait(stream, (status) => console.log(status.tag))
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Opstream] --> B[pear-opwait]
|
||||
B --> C[Observe status events]
|
||||
C --> D[Resolve final]
|
||||
C --> E[Reject on error]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `const opwait = require('pear-opwait')`
|
||||
|
||||
Exports a single function.
|
||||
|
||||
### `opwait(stream[, onstatus]) -> Promise<any>`
|
||||
|
||||
Wait for a status-emitting stream to finish.
|
||||
|
||||
**Parameters:**
|
||||
- `stream` (Readable): Emits `{ tag, data }` status objects.
|
||||
- `onstatus` (function, optional): Called for each status. May be async.
|
||||
|
||||
**Behavior:**
|
||||
- `tag === 'final'` stores the resolution value.
|
||||
- `tag === 'error'` destroys the stream with `ERR_OPERATION_FAILED`.
|
||||
- Promise resolves on `end` with last `final` (or `null` if none).
|
||||
- Promise rejects on `error` events.
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Await an Opstream
|
||||
|
||||
```js
|
||||
const opwait = require('pear-opwait')
|
||||
const Opstream = require('pear-opstream')
|
||||
|
||||
const stream = new Opstream(async () => {
|
||||
stream.final = { ok: true }
|
||||
})
|
||||
|
||||
const result = await opwait(stream)
|
||||
console.log(result.ok)
|
||||
```
|
||||
|
||||
### Example 2: Log Status Events
|
||||
|
||||
```js
|
||||
const opwait = require('pear-opwait')
|
||||
|
||||
await opwait(stream, (status) => {
|
||||
console.log(status.tag, status.data)
|
||||
})
|
||||
```
|
||||
|
||||
### Example 3: Async Status Observer
|
||||
|
||||
```js
|
||||
const opwait = require('pear-opwait')
|
||||
|
||||
await opwait(stream, async (status) => {
|
||||
if (status.tag === 'progress') {
|
||||
await writeProgress(status.data)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Example 4: Handling Operation Failure
|
||||
|
||||
```js
|
||||
const opwait = require('pear-opwait')
|
||||
|
||||
try {
|
||||
await opwait(stream)
|
||||
} catch (err) {
|
||||
console.error(err.code, err.message)
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Always attach `onstatus`** if you need progress logs.
|
||||
- **Avoid heavy work** in `onstatus` to keep streams responsive.
|
||||
- **Handle rejections** to report meaningful errors to users.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- The wrapper does minimal work; overhead is negligible.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Status events may contain sensitive data; avoid logging in untrusted contexts.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-opstream
|
||||
|
||||
`pear-opwait` is designed to consume `pear-opstream` status streams.
|
||||
|
||||
### With pear-errors
|
||||
|
||||
Logical operation failures are wrapped using `ERR_OPERATION_FAILED`.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- `ERR_OPERATION_FAILED` includes the original status payload as metadata.
|
||||
- Stream errors propagate directly to the promise rejection.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Utility | **Ecosystem Role**: Operation Awaiter | **Dependencies**: pear-errors
|
||||
@@ -0,0 +1,135 @@
|
||||
# pear-runtime-appling - Pear Runtime App Shell
|
||||
|
||||
## Overview
|
||||
|
||||
pear-runtime-appling defines the platform app shell (appling) for the Pear Runtime. It uses `cmake-pear` to generate macOS, Linux, and Windows app artifacts with consistent metadata, signing configuration, and branding assets.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Cross-platform app shell**: Generates native app bundles for macOS, Linux, Windows.
|
||||
- **CMake integration**: Uses `add_pear_appling` to declaratively define metadata.
|
||||
- **Signing metadata**: Embeds macOS and Windows signing identifiers.
|
||||
- **Branding assets**: Includes platform-specific icons and splash assets.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **Runtime packaging**: Build the Pear Runtime shell for distribution.
|
||||
- **OEM builds**: Customize metadata for white-label runtime shells.
|
||||
- **CI release steps**: Produce consistent platform-native app shells.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
bare-make generate
|
||||
bare-make build
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[CMakeLists.txt] --> B[cmake-pear]
|
||||
B --> C[add_pear_appling]
|
||||
C --> D[Platform app shell]
|
||||
D --> E[macOS .app]
|
||||
D --> F[Windows .exe/app]
|
||||
D --> G[Linux app bundle]
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
The build is defined via `add_pear_appling` in `CMakeLists.txt` with fields:
|
||||
|
||||
- `KEY runtime`: Pear link alias for the runtime.
|
||||
- `NAME "Pear Runtime"`: Human-friendly app name.
|
||||
- `VERSION 1.0.0`: Shell version (metadata).
|
||||
- `AUTHOR Holepunch`
|
||||
- `DESCRIPTION "Pear Runtime"`
|
||||
- `MACOS_IDENTIFIER com.pears.docs`
|
||||
- `MACOS_CATEGORY public.app-category.developer-tools`
|
||||
- `MACOS_SIGNING_IDENTITY ...`
|
||||
- `WINDOWS_SIGNING_SUBJECT ...`
|
||||
- `WINDOWS_SIGNING_THUMBPRINT ...`
|
||||
- `LINUX_CATEGORY Development`
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Build the Appling
|
||||
|
||||
```bash
|
||||
bare-make generate
|
||||
bare-make build
|
||||
```
|
||||
|
||||
### Example 2: Customize Metadata (Fork)
|
||||
|
||||
```cmake
|
||||
add_pear_appling(
|
||||
pear_runtime_appling
|
||||
KEY runtime
|
||||
NAME "My Runtime"
|
||||
VERSION 1.0.1
|
||||
AUTHOR "Acme"
|
||||
DESCRIPTION "Acme Runtime"
|
||||
LINUX_CATEGORY Development
|
||||
)
|
||||
```
|
||||
|
||||
### Example 3: Replace Icons
|
||||
|
||||
Place custom icons in:
|
||||
|
||||
- `assets/darwin/icon.png`
|
||||
- `assets/linux/icon.png`
|
||||
- `assets/win32/icon.png`
|
||||
|
||||
### Example 4: Integrate with pear-runtime-bootstrap
|
||||
|
||||
```bash
|
||||
# pear-runtime-bootstrap will consume build outputs
|
||||
node build.js
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Keep metadata stable** for a predictable app identity across releases.
|
||||
- **Provide platform icons** for consistent UX.
|
||||
- **Align signing identity** with your distribution certificate.
|
||||
- **Use CI** to build reproducible, signed shells.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- The app shell itself is lightweight; build time is dominated by platform tooling.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Validate signing identity values in CI to avoid unsigned releases.
|
||||
- Treat signing credentials as secrets and store securely.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-runtime-bootstrap
|
||||
|
||||
`pear-runtime-bootstrap` bundles the appling artifacts into platform builds.
|
||||
|
||||
### With cmake-pear
|
||||
|
||||
The build uses `cmake-pear`'s `add_pear_appling` helper to standardize packaging.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Build failures typically come from missing signing tools or CMake setup.
|
||||
- Check `bare-make` output for platform-specific errors.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Build Artifact | **Ecosystem Role**: Runtime Shell | **Dependencies**: cmake-pear
|
||||
@@ -0,0 +1,123 @@
|
||||
# pear-runtime-bare - Bare Runtime Host for Pear
|
||||
|
||||
## Overview
|
||||
|
||||
pear-runtime-bare is a native executable that hosts the Pear runtime on top of the Bare platform. It initializes a dedicated JS platform thread, loads the runtime bundle (preferring `.bundle` if present), and runs the Bare event loop with restart semantics.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Bare host executable**: Native binary that boots the Pear runtime.
|
||||
- **JS platform thread**: Dedicated platform thread for JS engine creation.
|
||||
- **Bundle resolution**: Loads `boot.bundle` if present, otherwise `boot.js`.
|
||||
- **Restart loop**: Supports a restart exit code to relaunch the runtime.
|
||||
- **Resource limits**: Increases open file limits where supported.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **Runtime packaging**: Core runtime binary for Pear distributions.
|
||||
- **Platform boot**: Embedded runtime in appling packaging flows.
|
||||
- **System integration**: Launchable binary for sidecar or CLI orchestration.
|
||||
|
||||
## Build
|
||||
|
||||
This module is built using CMake and `bare-dev` tooling:
|
||||
|
||||
```bash
|
||||
bare-make generate
|
||||
bare-make build
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[pear-runtime-bare] --> B[Initialize platform thread]
|
||||
B --> C[Create JS platform]
|
||||
A --> D[Bare loop]
|
||||
A --> E[Resolve boot.bundle/boot.js]
|
||||
E --> F[bare_load + bare_run]
|
||||
F --> G[bare_teardown]
|
||||
G -->|RESTART_EXIT_CODE| F
|
||||
```
|
||||
|
||||
## Runtime Flow
|
||||
|
||||
1. Set file descriptor limits and ignore SIGPIPE.
|
||||
2. Start a dedicated JS platform thread (`js_create_platform`).
|
||||
3. Resolve executable path and locate runtime root.
|
||||
4. Load `boot.bundle` if present, otherwise fallback to `boot.js`.
|
||||
5. Run the Bare event loop; on restart exit code, repeat.
|
||||
6. Shutdown platform and exit with the final exit code.
|
||||
|
||||
## Build Configuration
|
||||
|
||||
Key CMake configuration elements:
|
||||
|
||||
- Fetches `bare`, `libpath`, and `librlimit`.
|
||||
- Links `bare_static` into the executable.
|
||||
- Applies platform-specific code signing on macOS and Windows.
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Build the Runtime Binary
|
||||
|
||||
```bash
|
||||
bare-make generate
|
||||
bare-make build
|
||||
```
|
||||
|
||||
### Example 2: Run the Binary
|
||||
|
||||
```bash
|
||||
./build/pear-runtime
|
||||
```
|
||||
|
||||
### Example 3: Bundle vs JS Boot
|
||||
|
||||
```text
|
||||
runtime-root/
|
||||
boot.bundle # preferred if present
|
||||
boot.js # fallback
|
||||
```
|
||||
|
||||
### Example 4: Restart Semantics
|
||||
|
||||
If the runtime exits with code `75`, the host restarts the runtime loop.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Ship boot.bundle** for faster startup and fewer file reads.
|
||||
- **Keep boot.js as fallback** for developer builds.
|
||||
- **Use signing** for release builds to avoid OS trust warnings.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Startup cost includes JS platform creation and bundle loading.
|
||||
- Bundled boot can reduce IO and improve cold start.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- The runtime loads code from the runtime directory; ensure it is trusted.
|
||||
- Ensure signing identities and entitlements are correct for distribution.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-runtime-appling
|
||||
|
||||
`pear-runtime-bare` is packaged into the runtime app shell produced by `pear-runtime-appling` and bundled by `pear-runtime-bootstrap`.
|
||||
|
||||
### With bare
|
||||
|
||||
Uses Bare APIs (`bare_setup`, `bare_load`, `bare_run`, `bare_teardown`) to host the runtime.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Assertions guard critical failures; in production builds ensure logs capture failures.
|
||||
- Missing boot files will cause load errors; validate runtime directory layout.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Runtime Binary | **Ecosystem Role**: Runtime Host | **Dependencies**: bare, libpath, librlimit
|
||||
@@ -0,0 +1,144 @@
|
||||
# pear-runtime-bootstrap - Build and Package Pear Runtime
|
||||
|
||||
## Overview
|
||||
|
||||
pear-runtime-bootstrap is a small script-based toolchain to build and package the Pear runtime across platforms. It orchestrates `bare-dev` builds for native components, builds the Electron-based runtime app, and assembles a `build/` output directory. It can then pack the build into a gzipped tarball with `by-arch` layout.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Multi-component build**: Builds libappling, pear-runtime-bare, wakeup, and electron-runtime.
|
||||
- **Platform-aware**: Handles macOS, Linux, and Windows layout differences.
|
||||
- **Packaging**: Produces `build.tar.gz` with `by-arch/<platform-arch>` layout.
|
||||
- **Minimal entrypoints**: `build.js` and `pack.js` scripts.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **Runtime release pipeline**: Build runtime artifacts for distribution.
|
||||
- **CI packaging**: Produce per-arch bundles for update systems.
|
||||
- **Developer builds**: Quick local runtime build.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
node build.js
|
||||
```
|
||||
|
||||
## Pack
|
||||
|
||||
```bash
|
||||
node pack.js
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[build.js] --> B[bare-dev vendor sync]
|
||||
A --> C[libappling build]
|
||||
A --> D[pear-runtime-bare build]
|
||||
A --> E[wakeup build]
|
||||
A --> F[electron-runtime build]
|
||||
A --> G[build/ layout]
|
||||
H[pack.js] --> I[tar.gz output]
|
||||
```
|
||||
|
||||
## Build Output Layout
|
||||
|
||||
`build/` contains:
|
||||
|
||||
- `build/bin/` (runtime binaries and app bundle)
|
||||
- `build/lib/` (libappling launch library)
|
||||
|
||||
`pack.js` produces `build.tar.gz` with entries under:
|
||||
|
||||
```
|
||||
by-arch/<platform-arch>/...
|
||||
```
|
||||
|
||||
## Script Details
|
||||
|
||||
### `build.js`
|
||||
|
||||
- Runs `bare-dev vendor sync`.
|
||||
- Builds:
|
||||
- `vendor/libappling` (via npm + bare-dev)
|
||||
- `vendor/pear-runtime-bare` (via bare-dev + CMake install)
|
||||
- `vendor/wakeup` (via bare-dev + CMake install)
|
||||
- `vendor/electron-runtime` (via npm dist)
|
||||
- Copies artifacts into `build/bin` and `build/lib` with platform-specific naming.
|
||||
|
||||
### `pack.js`
|
||||
|
||||
- Streams `build/` into a gzipped tarball.
|
||||
- Prefixes all entries with `by-arch/<platform>-<arch>/`.
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Build on macOS
|
||||
|
||||
```bash
|
||||
npm install
|
||||
node build.js
|
||||
```
|
||||
|
||||
### Example 2: Package for Distribution
|
||||
|
||||
```bash
|
||||
node pack.js
|
||||
ls build.tar.gz
|
||||
```
|
||||
|
||||
### Example 3: Inspect Build Output
|
||||
|
||||
```bash
|
||||
ls build/bin
|
||||
ls build/lib
|
||||
```
|
||||
|
||||
### Example 4: Customizing Artifacts
|
||||
|
||||
Fork and adjust `build.js` to alter the output layout or include extra binaries.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Run on target OS** for native artifacts.
|
||||
- **Use clean build directories** to avoid stale files.
|
||||
- **Keep vendor submodules in sync** with the runtime version.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Electron runtime builds are the slowest stage.
|
||||
- Using CI caching for `vendor/` and npm installs significantly reduces build time.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Ensure the build environment is trusted and locked down.
|
||||
- Verify signing identities for macOS/Windows builds.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-runtime-appling
|
||||
|
||||
The appling shell is built in `vendor/` and moved into `build/bin`.
|
||||
|
||||
### With pear-updater
|
||||
|
||||
The `build.tar.gz` output can be served to the updater for runtime updates.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Missing build tools (`bare-dev`, `cmake`, `npm`) will cause failures early.
|
||||
- Platform mismatches will break artifact path assumptions.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Build Tool | **Ecosystem Role**: Runtime Packaging | **Dependencies**: shellblazer, tar-fs, which-runtime
|
||||
@@ -0,0 +1,124 @@
|
||||
# pear-tryboot - Sidecar Auto-Start Helper
|
||||
|
||||
## Overview
|
||||
|
||||
pear-tryboot is a small helper used with `pear-ipc` to auto-start the Pear sidecar if it is not already running. It spawns the runtime binary with `--sidecar` and forwards optional DHT bootstrap arguments.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Sidecar spawn**: Launches Pear runtime with `--sidecar`.
|
||||
- **Argument passthrough**: Forwards `--dht-bootstrap` when present.
|
||||
- **Portable**: Uses `bare-daemon` to spawn detached processes.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **IPC auto-connect**: Ensure sidecar is running before IPC connection.
|
||||
- **CLI tools**: Start Pear runtime on-demand.
|
||||
- **Desktop integrations**: Launch sidecar in the background.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-tryboot
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const IPC = require('pear-ipc')
|
||||
const tryboot = require('pear-tryboot')
|
||||
|
||||
const client = new IPC.Client({
|
||||
socketPath: '/tmp/pear.sock',
|
||||
connect: tryboot
|
||||
})
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[IPC connect] --> B[pear-tryboot]
|
||||
B --> C[bare-daemon.spawn]
|
||||
C --> D[Pear runtime --sidecar]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `const tryboot = require('pear-tryboot')`
|
||||
|
||||
Exports a single function.
|
||||
|
||||
### `tryboot()`
|
||||
|
||||
Spawns the Pear runtime sidecar using `bare-daemon`.
|
||||
|
||||
**Behavior:**
|
||||
- Uses `pear-constants` for `RUNTIME` binary and `PLATFORM_DIR`.
|
||||
- Adds `--sidecar` to args.
|
||||
- If `--dht-bootstrap` is present in argv, forwards it to the runtime.
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Basic Sidecar Spawn
|
||||
|
||||
```js
|
||||
const tryboot = require('pear-tryboot')
|
||||
tryboot()
|
||||
```
|
||||
|
||||
### Example 2: With pear-ipc Client
|
||||
|
||||
```js
|
||||
const IPC = require('pear-ipc')
|
||||
const tryboot = require('pear-tryboot')
|
||||
|
||||
const client = new IPC.Client({
|
||||
socketPath: '/tmp/pear.sock',
|
||||
connect: tryboot
|
||||
})
|
||||
```
|
||||
|
||||
### Example 3: CLI Context with DHT Bootstrap
|
||||
|
||||
```bash
|
||||
pear --dht-bootstrap 1.2.3.4:49737
|
||||
```
|
||||
|
||||
In this case, `pear-tryboot` forwards the `--dht-bootstrap` arg.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Use only for Pear runtime**; it assumes Pear sidecar semantics.
|
||||
- **Pass socket path** via IPC settings, not via tryboot.
|
||||
- **Avoid double-spawning** by using `pear-ipc` connection checks.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Spawn cost is OS-dependent; it is intended for cold-start scenarios.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Ensure the runtime binary path is trusted (`pear-constants`).
|
||||
- Be careful passing bootstrap nodes from untrusted input.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-ipc
|
||||
|
||||
`pear-tryboot` is designed to be passed as the `connect` handler for `pear-ipc` clients.
|
||||
|
||||
### With pear-constants
|
||||
|
||||
Uses `RUNTIME` and `PLATFORM_DIR` to locate the runtime binary and working directory.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Errors from `bare-daemon.spawn` may surface if the runtime is missing or permissions are insufficient.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Utility | **Ecosystem Role**: Sidecar Boot | **Dependencies**: bare-daemon, pear-constants
|
||||
@@ -0,0 +1,139 @@
|
||||
# pear-updater-bootstrap - Bootstrap Runtime Updates
|
||||
|
||||
## Overview
|
||||
|
||||
pear-updater-bootstrap bootstraps the Pear runtime updater from a known drive key. It sets up a Corestore + Hyperdrive, joins Hyperswarm to replicate updates, waits for the first valid checkout, and applies the update locally. It also provides a CLI and a device-file validation helper.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **One-shot bootstrap**: Downloads enough data to apply the first update.
|
||||
- **Swarm replication**: Uses Hyperswarm to replicate the runtime drive.
|
||||
- **Lock and swap support**: Optional locking and swap handling.
|
||||
- **CLI interface**: Simple `pear-updater-bootstrap <key> <dir>`.
|
||||
- **Validation**: Checks the platform Corestore device file.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **First-time install**: Populate runtime files on a new system.
|
||||
- **Recovery tooling**: Rebuild the runtime directory from a key.
|
||||
- **CI images**: Prepopulate runtime on build machines.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-updater-bootstrap
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const bootstrap = require('pear-updater-bootstrap')
|
||||
|
||||
await bootstrap(key, '/opt/pear')
|
||||
```
|
||||
|
||||
## CLI
|
||||
|
||||
```bash
|
||||
pear-updater-bootstrap <key> <platform-dir>
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[bootstrap()] --> B[Corestore + Hyperdrive]
|
||||
A --> C[PearUpdater]
|
||||
A --> D[Hyperswarm join]
|
||||
D --> E[Replicate data]
|
||||
A --> F[u.wait(min length)]
|
||||
A --> G[u.applyUpdate()]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `await bootstrap(key, directory = 'pear', opts)`
|
||||
|
||||
**Parameters:**
|
||||
- `key` (string|Buffer, required): Drive key for runtime updates.
|
||||
- `directory` (string): Platform directory (default `pear`).
|
||||
- `opts.lock` (boolean): Create lock file (default true).
|
||||
- `opts.bootstrap` (array): Hyperswarm bootstrap nodes.
|
||||
- `opts.onupdater` (function): Callback with updater instance.
|
||||
- `opts.onapply` (function): Called before apply.
|
||||
- `opts.length` (number): Initial checkout length.
|
||||
- `opts.fork` (number): Initial checkout fork.
|
||||
- `opts.force` (boolean): Force update even if current exists.
|
||||
- `opts.host` (string): Override host triplet.
|
||||
|
||||
### `bootstrap.validate(directory) -> Promise<boolean>`
|
||||
|
||||
Validates the Corestore device file in the platform directory.
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Basic Bootstrap
|
||||
|
||||
```js
|
||||
await bootstrap('pzcjqm...')
|
||||
```
|
||||
|
||||
### Example 2: Custom Platform Directory
|
||||
|
||||
```js
|
||||
await bootstrap('pzcjqm...', '/opt/pear-runtime')
|
||||
```
|
||||
|
||||
### Example 3: Custom Bootstrap Nodes
|
||||
|
||||
```js
|
||||
await bootstrap('pzcjqm...', '/opt/pear', {
|
||||
bootstrap: [{ host: '1.2.3.4', port: 49737 }]
|
||||
})
|
||||
```
|
||||
|
||||
### Example 4: Validate Platform Directory
|
||||
|
||||
```js
|
||||
const ok = await bootstrap.validate('/opt/pear')
|
||||
console.log('valid', ok)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Provide a stable directory** to avoid conflicting installs.
|
||||
- **Use lockfiles** when multiple processes may bootstrap.
|
||||
- **Close resources** if you wrap `bootstrap` in higher-level flows.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Initial bootstrap downloads only what is needed to reach the first checkout.
|
||||
- Network latency dominates the first update on cold installs.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Only use trusted keys; updates are not automatically signed here.
|
||||
- Restrict bootstrap nodes if you operate on private networks.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-updater
|
||||
|
||||
Internally constructs `pear-updater` and uses `wait` + `applyUpdate`.
|
||||
|
||||
### With hyperswarm
|
||||
|
||||
Uses Hyperswarm to replicate the runtime drive from peers.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Missing `key` throws immediately.
|
||||
- Network issues can prevent reaching the first checkout.
|
||||
- Filesystem errors surface during swap or lock creation.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Bootstrap Tool | **Ecosystem Role**: Runtime Install | **Dependencies**: hyperdrive, hyperswarm, pear-updater
|
||||
@@ -0,0 +1,182 @@
|
||||
# pear-updater - Runtime Update Engine
|
||||
|
||||
## Overview
|
||||
|
||||
pear-updater is the update engine used by the Pear runtime. It watches a Hyperdrive for new releases, downloads required assets, bundles the runtime entrypoint, manages per-arch swap directories, and applies updates atomically. It exposes progress metrics and a stream-based watch API for update events.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Drive-backed updates**: Watches a Hyperdrive for new checkouts.
|
||||
- **Per-arch updates**: Supports `by-arch/<host>` layouts.
|
||||
- **Atomic swaps**: Updates swap directories and symlinks safely.
|
||||
- **Bundling**: Produces `.bundle` files via `drive-bundler` and `bare-bundle`.
|
||||
- **Progress metrics**: Tracks downloaded/uploaded blocks and speed.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **Runtime self-update**: Apply updates in the Pear runtime.
|
||||
- **Custom update services**: Embed into other updatable runtimes.
|
||||
- **CI/CD deploy**: Automate runtime release channels.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-updater
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const PearUpdater = require('pear-updater')
|
||||
|
||||
const updater = new PearUpdater(drive, {
|
||||
directory: '/opt/pear',
|
||||
swap: '/opt/pear/current/0',
|
||||
checkout: { key, length: 0, fork: 0 }
|
||||
})
|
||||
|
||||
updater.on('update', (checkout) => console.log('updated', checkout))
|
||||
await updater.update()
|
||||
await updater.applyUpdate()
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Hyperdrive] --> B[PearUpdater]
|
||||
B --> C[watch() stream]
|
||||
B --> D[update()]
|
||||
D --> E[download by-arch assets]
|
||||
D --> F[bundle entrypoint]
|
||||
D --> G[swap directory]
|
||||
B --> H[applyUpdate()]
|
||||
H --> I[atomic symlink/rename]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `new PearUpdater(drive, opts)`
|
||||
|
||||
**Parameters:**
|
||||
- `drive` (Hyperdrive): Drive containing runtime bundles and assets.
|
||||
- `opts.directory` (string, required): Base runtime directory.
|
||||
- `opts.checkout` (object): Current checkout `{ key, length, fork }`.
|
||||
- `opts.swap` (string): Swap directory path.
|
||||
- `opts.lock` (string|null): Lockfile path for update synchronization.
|
||||
- `opts.host` (string): Host triplet (default `platform-arch`).
|
||||
- `opts.byArch` (boolean): Use `by-arch/<host>` layout (default true).
|
||||
- `opts.force` (boolean): Force update even if checkout unchanged.
|
||||
- Hooks: `onupdating`, `onupdate`, `onapply` (async callbacks).
|
||||
|
||||
### `await updater.update()`
|
||||
|
||||
Fetch and prepare the latest update. Emits `updating` and `update` events.
|
||||
|
||||
### `await updater.applyUpdate()`
|
||||
|
||||
Apply a prepared update atomically. Returns checkout or `null` if none.
|
||||
|
||||
### `updater.watch(opts) -> Readable`
|
||||
|
||||
Stream of checkout objects as updates land.
|
||||
|
||||
### `await updater.wait(minCheckout, opts)`
|
||||
|
||||
Wait until a checkout reaches a minimum `{ length, fork }`.
|
||||
|
||||
### Status and Metrics
|
||||
|
||||
- `updater.status`: `waiting`, `updating-assets`, `updating-bundle`, `updated`.
|
||||
- `downloadedBlocks`, `downloadedBlocksEstimate`.
|
||||
- `downloadedBytes`, `downloadSpeed()`.
|
||||
- `uploadedBlocks`, `uploadedBytes`, `uploadSpeed()`.
|
||||
- `downloadProgress` (0..1; capped at 0.9 while downloading).
|
||||
|
||||
## Events
|
||||
|
||||
- `updating(checkout, old)`
|
||||
- `update(checkout, old)`
|
||||
- `update-applied(checkout)`
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Watch for Updates
|
||||
|
||||
```js
|
||||
for await (const checkout of updater.watch()) {
|
||||
console.log('new checkout', checkout)
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Wait for Minimum Version
|
||||
|
||||
```js
|
||||
await updater.wait({ length: 100, fork: 0 })
|
||||
```
|
||||
|
||||
### Example 3: Observe Progress
|
||||
|
||||
```js
|
||||
updater.on('updating', () => {
|
||||
console.log('status', updater.status)
|
||||
})
|
||||
|
||||
const interval = setInterval(() => {
|
||||
console.log('download', updater.downloadProgress)
|
||||
}, 500)
|
||||
|
||||
updater.on('update', () => clearInterval(interval))
|
||||
```
|
||||
|
||||
### Example 4: Custom Hooks
|
||||
|
||||
```js
|
||||
const updater = new PearUpdater(drive, {
|
||||
directory: '/opt/pear',
|
||||
onupdating: async () => console.log('pre-update'),
|
||||
onupdate: async () => console.log('post-update'),
|
||||
onapply: async () => console.log('apply')
|
||||
})
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Provide a lockfile** to prevent multiple updaters from racing.
|
||||
- **Use by-arch layout** to minimize update size.
|
||||
- **Call `applyUpdate`** only after `update` completed.
|
||||
- **Observe `update` events** for reactive UI or logging.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- `by-arch` diffs limit downloads to changed blobs.
|
||||
- Large updates can trigger a full mirror fallback.
|
||||
- Bundling uses `drive-bundler` and `bare-bundle` and may be CPU-heavy.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Ensure the drive content is trusted (sign or verify checkouts externally).
|
||||
- Avoid downgrades; updater enforces ABI compatibility and prevents rollback.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-updater-bootstrap
|
||||
|
||||
`pear-updater-bootstrap` sets up a Hyperdrive and invokes `pear-updater` to perform the first update.
|
||||
|
||||
### With drive-bundler
|
||||
|
||||
`drive-bundler` creates runtime bundles used to boot the updated runtime.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Missing `directory` throws on construction.
|
||||
- ABI incompatibility throws when no compatible update exists.
|
||||
- Filesystem errors surface during swap updates or bundle writes.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Runtime Service | **Ecosystem Role**: Updater | **Dependencies**: drive-bundler, bare-bundle, localdrive
|
||||
@@ -0,0 +1,154 @@
|
||||
# pear-wakeups - Pear Wakeup Event Stream
|
||||
|
||||
## Overview
|
||||
|
||||
pear-wakeups provides a stream of wakeup events inside a Pear application. Wakeups are triggered by trusted `pear://` link clicks or detached runs, and include metadata such as link fragments and entrypoints. The module is a thin wrapper over `pear-messages` with a `type: 'pear/wakeup'` pattern.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Wakeup stream**: Listen for app wakeup events.
|
||||
- **IPC-based**: Uses Pear runtime IPC.
|
||||
- **Simple API**: Returns a readable stream or accepts a listener.
|
||||
- **Standard payload**: Consistent `wakeup` object shape.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **Deep-link handling**: React to external link clicks.
|
||||
- **Detached run signals**: Handle `pear run --detached` wakeups.
|
||||
- **App focus events**: Use wakeups to bring UI to foreground.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-wakeups
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const wakeups = require('pear-wakeups')
|
||||
|
||||
wakeups((wakeup) => {
|
||||
console.log(wakeup.link, wakeup.entrypoint)
|
||||
})
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Platform wakeup] --> B[pear-message bus]
|
||||
B --> C[pear-wakeups]
|
||||
C --> D[Readable stream]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `const wakeups = require('pear-wakeups')`
|
||||
|
||||
Exports a single function.
|
||||
|
||||
### `wakeups([listener]) -> Readable`
|
||||
|
||||
Subscribe to wakeup events.
|
||||
|
||||
**Parameters:**
|
||||
- `listener` (function, optional): Called for each wakeup.
|
||||
|
||||
**Returns:**
|
||||
- `Readable` stream emitting wakeup objects.
|
||||
|
||||
**Throws:**
|
||||
- Error if IPC is missing: `pear-wakeups is designed for Pear - IPC missing`.
|
||||
|
||||
## Wakeup Object Shape
|
||||
|
||||
```js
|
||||
{
|
||||
type: 'pear/wakeup',
|
||||
link: <String>,
|
||||
linkData: <String>,
|
||||
fragment: <String>,
|
||||
entrypoint: <String>
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Stream Listener
|
||||
|
||||
```js
|
||||
const wakeups = require('pear-wakeups')
|
||||
|
||||
const stream = wakeups()
|
||||
stream.on('data', (w) => console.log('wakeup', w))
|
||||
```
|
||||
|
||||
### Example 2: Listener Shortcut
|
||||
|
||||
```js
|
||||
const wakeups = require('pear-wakeups')
|
||||
|
||||
wakeups((w) => {
|
||||
console.log('link', w.link)
|
||||
})
|
||||
```
|
||||
|
||||
### Example 3: Parse Wakeup Link Data
|
||||
|
||||
```js
|
||||
const wakeups = require('pear-wakeups')
|
||||
|
||||
wakeups((w) => {
|
||||
const parts = w.linkData?.split('/') || []
|
||||
console.log('entry', parts[0])
|
||||
})
|
||||
```
|
||||
|
||||
### Example 4: Pair with pear-link
|
||||
|
||||
```js
|
||||
const wakeups = require('pear-wakeups')
|
||||
const plink = require('pear-link')
|
||||
|
||||
wakeups((w) => {
|
||||
const parsed = plink.parse(w.link)
|
||||
console.log(parsed.drive.key)
|
||||
})
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Filter by entrypoint** if multiple routes exist.
|
||||
- **Normalize links** using `pear-link` when comparing wakeup links.
|
||||
- **Avoid heavy work** in the listener to keep wakeup handling responsive.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Wakeup events are low volume and lightweight.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Treat wakeup payloads as untrusted; validate link data.
|
||||
- Only trusted `pear://` links should trigger wakeups.
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
### With pear-messages
|
||||
|
||||
`pear-wakeups` uses `pear-messages` with `{ type: 'pear/wakeup' }`.
|
||||
|
||||
### With pear-link
|
||||
|
||||
Parse wakeup `link` values for routing and metadata.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Missing IPC throws immediately; ensure you run inside Pear runtime.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Runtime Helper | **Ecosystem Role**: Wakeup Events | **Dependencies**: pear-messages
|
||||
Reference in New Issue
Block a user