Sync KB with holepunchto_repos (600 modules, inventory scripts)
- Add scripts/build-module-inventory.mjs and module-inventory.json - Add generate-new-module-stubs.mjs for new repo docs; sync-title-semver helper - Document 48 previously missing packages; remove duplicate storage/rocksdb.md - Refresh Tier A stack versions and Pear/Bare runtime notes (CLI vs pear-runtime) - Update README, architecture, interconnections, project ideas for 600-repo scale - Test projects: refresh locks, ignore/remove node_modules, add test-projects README - Extend dev-diary and scripts/README with maintenance checklist Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Dependencies (regenerate with npm install in each project)
|
||||
**/node_modules/
|
||||
@@ -1,10 +1,10 @@
|
||||
# Holepunch / Hypercore Ecosystem KB 🦞
|
||||
|
||||
**Comprehensive developer knowledge base** on the full Holepunch.to / Hypercore Protocol stack (554+ repositories analyzed).
|
||||
**Comprehensive developer knowledge base** on the full Holepunch.to / Hypercore Protocol stack (**600** upstream repositories mirrored under `holepunchto_repos/`; see `scripts/module-inventory.json`).
|
||||
|
||||
## Overview
|
||||
|
||||
The **Holepunch ecosystem** is a comprehensive peer-to-peer (P2P) application platform built from 554+ open-source repositories. It provides everything needed to build, distribute, and run decentralized applications across desktop, mobile, and embedded platforms. The ecosystem is designed from the ground up for P2P operation, with no reliance on central servers for core functionality.
|
||||
The **Holepunch ecosystem** is a comprehensive peer-to-peer (P2P) application platform built from **600+** open-source repositories in the Holepunch.to GitHub org (local mirror used for KB refresh). It provides everything needed to build, distribute, and run decentralized applications across desktop, mobile, and embedded platforms. The ecosystem is designed from the ground up for P2P operation, with no reliance on central servers for core functionality.
|
||||
|
||||
### What is Holepunch?
|
||||
|
||||
@@ -119,7 +119,7 @@ The ecosystem powers production applications:
|
||||
|
||||
| Category | Count |
|
||||
|----------|-------|
|
||||
| Total Repositories | 554+ |
|
||||
| Total Repositories | 600+ |
|
||||
| Hyper* modules | 100+ |
|
||||
| Bare runtime modules | 100+ |
|
||||
| Pear platform modules | 80+ |
|
||||
@@ -191,9 +191,9 @@ await core.append(Buffer.from('Hello P2P World!'))
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total Repositories | 554+ |
|
||||
| Total Repositories | 600+ |
|
||||
| Total Documentation | 50,000+ lines |
|
||||
| Modules Covered | 553/553 (100%) |
|
||||
| Modules Covered | 600 module articles (`modules/`); inventory in `scripts/module-inventory.json` |
|
||||
| Categories | 12 |
|
||||
|
||||
---
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The Holepunch ecosystem is a comprehensive peer-to-peer (P2P) application stack spanning 554+ repositories. It provides everything needed to build, distribute, and run distributed applications across desktop and mobile platforms.
|
||||
The Holepunch ecosystem is a comprehensive peer-to-peer (P2P) application stack spanning **600+** repositories (see `research/scripts/module-inventory.json` for the mirrored set). It provides everything needed to build, distribute, and run distributed applications across desktop and mobile platforms.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
@@ -755,7 +755,7 @@ flowchart TB
|
||||
|
||||
## Repository Statistics
|
||||
|
||||
- **Total Repositories**: 554+
|
||||
- **Total Repositories**: 600+
|
||||
- **Core Ecosystem**: 100+ hyper* modules
|
||||
- **Bare Runtime**: 100+ bare* modules
|
||||
- **Pear Platform**: 80+ pear* modules
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Holepunch R&D Dev Diary
|
||||
|
||||
Log of heartbeat runs, project progress, fixes, new apps.
|
||||
|
||||
## Format
|
||||
|
||||
**Run #N | Date/Time**
|
||||
|
||||
- Projects checked/completed/updated
|
||||
- New projects started
|
||||
- Commits/pushes
|
||||
- Insights/TODOs
|
||||
|
||||
---
|
||||
|
||||
## KB sync checklist (`research/` vs `holepunchto_repos`)
|
||||
|
||||
After pulling upstream mirrors (about monthly):
|
||||
|
||||
1. `cd research && node scripts/build-module-inventory.mjs` — confirm `undocumentedClones` is empty in `scripts/module-inventory.json`.
|
||||
2. For new repos: extend `scripts/generate-new-module-stubs.mjs` `CATEGORY` map and re-run, or add `modules/<area>/<repo>.md` by hand.
|
||||
3. `node scripts/sync-title-semver.mjs` — refreshes `vsemver` in the first line of docs under `storage/`, `native/`, `utilities/`, and `tooling/` when it diverges from `package.json`.
|
||||
4. Re-read **Tier A** changelogs (`hypercore`, `hyperdrive`, `autobase`, `hyperswarm`, `hyperdht`, `corestore`, `protomux`, …) for API or security notes.
|
||||
5. **Pear**: diff `holepunchto_repos/pear/CHANGELOG.md` against `modules/utilities/pear.md` and `modules/pear/` for CLI vs `pear-runtime` wording.
|
||||
6. `test-projects/`*: run `npm install`, commit lockfiles; keep `node_modules` untracked (root `.gitignore`).
|
||||
|
||||
@@ -52,6 +52,18 @@ flowchart TB
|
||||
|
||||
---
|
||||
|
||||
## 0. Distribution and runtime (2026)
|
||||
|
||||
Pear applications today are often shipped with **embeddable runtimes** and packaging helpers that sit beside the classic Hypercore + Hyperswarm stack:
|
||||
|
||||
- **[`pear-runtime`](../modules/pear/pear-runtime.md)**, **[`pear-runtime-updater`](../modules/pear/pear-runtime-updater.md)**, and **[`pear-runtime-legacy-storage`](../modules/pear/pear-runtime-legacy-storage.md)** — split runtime/updater pieces aligned with modern Pear CLI releases (see upstream `pear` changelog for `pear run` CLI deprecation in favor of `pear-runtime`).
|
||||
- **[`bundlebee`](../modules/pear/bundlebee.md)** / **[`bundlebee-cli`](../modules/pear/bundlebee-cli.md)** — multi-architecture deployment bundles.
|
||||
- **[`distributed-drive`](../modules/storage/distributed-drive.md)** — shared drive utilities used in larger compositions.
|
||||
|
||||
These modules still **compose with** Hypercore, Corestore, and Hyperswarm; they change *how binaries and updates are staged*, not the replication protocol itself.
|
||||
|
||||
---
|
||||
|
||||
## 1. Hypercore + Hyperswarm
|
||||
|
||||
### 1.1 Pattern Overview
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
# bare-addon-java
|
||||
|
||||
**Package**: `bare-addon-java` · **Version**: v1.0.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Example Bare addon.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bare-addon-java](https://github.com/holepunchto/bare-addon-java)
|
||||
- Local mirror: `holepunchto_repos/bare-addon-java`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bare-addon-java
|
||||
|
||||
Template repository for creating Bare native addons using Java via <https://github.com/holepunchto/libjnitl>. For information on how to use the template, see [Creating a repository from a template](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template).
|
||||
|
||||
## Building
|
||||
|
||||
<https://github.com/holepunchto/bare-make> is used for compiling the native bindings in [`binding.cc`](binding.cc). Start by installing the tool globally:
|
||||
|
||||
```console
|
||||
npm i -g bare-make
|
||||
```
|
||||
|
||||
Next, generate the build system for compiling the bindings, optionally setting the `--debug` flag to enable debug symbols and assertions:
|
||||
|
||||
```console
|
||||
bare-make generate [--debug]
|
||||
```
|
||||
|
||||
This only has to be run once per repository checkout. When updating `bare-make` or your compiler toolchain it might also be necessary to regenerate the build system. To do so, run the command again with the `--no-cache` flag set to disregard the existing build system cache:
|
||||
|
||||
```console
|
||||
bare-make generate [--debug] --no-cache
|
||||
```
|
||||
|
||||
With a build system generated, the bindings can be compiled:
|
||||
|
||||
```console
|
||||
bare-make build
|
||||
```
|
||||
|
||||
This will compile the bindings and output the resulting shared library module to the `build/` directory. To install it into the `prebuilds/` directory where the Bare addon resolution algorithm expects to find it, do:
|
||||
|
||||
```console
|
||||
bare-make install
|
||||
```
|
||||
|
||||
To make iteration faster during development, the shared library module can also be linked into the `prebuilds/` directory rather than copied. To do so, set the `--link` flag:
|
||||
|
||||
```console
|
||||
bare-make install --link
|
||||
```
|
||||
|
||||
Prior to publishing the module, make sure that no links exist within the `prebuilds/` directory as these will not be included in the resulting package archive.
|
||||
|
||||
## Publishing
|
||||
|
||||
To publish an addon, make sure to first compile bindings for the targets you wish to support. The prebuild workflow defined in [`.github/workflows/prebuild.yml`](.github/workflows/prebuild.yml) automates this process for all [tier 1 targets](https://github.com/holepunchto/bare#platform-support) supported by Bare. The whole process can be handily orchestrated by the [GitHub CLI](https://cli.github.com). As the package version is part of the compiled bindings, make sure to first commit and push a version update:
|
||||
|
||||
```console
|
||||
npm version <increment>
|
||||
git push
|
||||
git push --tags
|
||||
```
|
||||
|
||||
To start the prebuild workflow for the newly pushed version, do:
|
||||
|
||||
```console
|
||||
gh workflow run prebuild --ref <version>
|
||||
```
|
||||
|
||||
To watch the status of the workflow run until it finishes, do:
|
||||
|
||||
```console
|
||||
gh run watch
|
||||
```
|
||||
|
||||
When finished, the resulting prebuilds can be downloaded to the `prebuilds/` directory by doing:
|
||||
|
||||
```console
|
||||
gh run download --name prebuilds --dir prebuilds
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You still need to manually run `npm pub` to publish the package to npm.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Addons are rarely self-contained and most often need to pull in external native libraries. For this, <https://github.com/holepunchto/cmake-fetch> should be used and is already available in this template as a development dependency.
|
||||
|
||||
To fetch an external native library, such as <https://github.com/holepunchto/liburl>, add the following line _after_ the `project()` declaration in the build definition:
|
||||
|
||||
```cmake
|
||||
fetch_package("github:holepunchto/liburl")
|
||||
```
|
||||
|
||||
Finally, link the imported native library to the addon:
|
||||
|
||||
```cmake
|
||||
target_link_libraries(
|
||||
${bare_addon}
|
||||
PUBLIC
|
||||
url
|
||||
)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,164 @@
|
||||
# bare-bluetooth-android
|
||||
|
||||
**Package**: `bare-bluetooth-android` · **Version**: v0.1.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Android Bluetooth bindings for Bare.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bare-bluetooth-android](https://github.com/holepunchto/bare-bluetooth-android)
|
||||
- Local mirror: `holepunchto_repos/bare-bluetooth-android`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bare-bluetooth-android
|
||||
|
||||
Android Bluetooth Low Energy (BLE) bindings for Bare, providing both central and peripheral roles. Built on the Android Bluetooth API.
|
||||
|
||||
```
|
||||
npm i bare-bluetooth-android
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const { Central } = require('bare-bluetooth-android')
|
||||
|
||||
const central = new Central()
|
||||
|
||||
central.on('stateChange', (state) => {
|
||||
if (state === 'on') {
|
||||
central.startScan(['180D']) // Heart Rate service UUID
|
||||
}
|
||||
})
|
||||
|
||||
central.on('discover', (peripheral) => {
|
||||
console.log('Found:', peripheral.name, peripheral.id)
|
||||
central.stopScan()
|
||||
central.connect(peripheral)
|
||||
})
|
||||
|
||||
central.on('connect', (peripheral) => {
|
||||
peripheral.discoverServices()
|
||||
|
||||
peripheral.on('servicesDiscover', (services) => {
|
||||
// Discover characteristics for each service
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const central = new Central()`
|
||||
|
||||
Create a new BLE central manager for scanning and connecting to peripherals.
|
||||
|
||||
#### `central.state`
|
||||
|
||||
The current Bluetooth adapter state. One of `'off'`, `'turningOn'`, `'on'`, or `'turningOff'`.
|
||||
|
||||
#### `central.startScan(serviceUUIDs[, opts])`
|
||||
|
||||
Start scanning for peripherals advertising the given `serviceUUIDs`. Pass `null` to scan for all peripherals.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
opts = {
|
||||
scanMode: null
|
||||
}
|
||||
```
|
||||
|
||||
Set `scanMode` to one of `Central.SCAN_MODE_OPPORTUNISTIC`, `Central.SCAN_MODE_LOW_POWER`, `Central.SCAN_MODE_BALANCED`, or `Central.SCAN_MODE_LOW_LATENCY`.
|
||||
|
||||
#### `central.stopScan()`
|
||||
|
||||
Stop scanning for peripherals.
|
||||
|
||||
#### `central.connect(peripheral)`
|
||||
|
||||
Connect to a discovered `peripheral`.
|
||||
|
||||
#### `central.disconnect(peripheral)`
|
||||
|
||||
Disconnect from a connected `peripheral`.
|
||||
|
||||
#### `central.destroy()`
|
||||
|
||||
Destroy the central manager, disconnecting all connected peripherals.
|
||||
|
||||
#### `event: 'stateChange'`
|
||||
|
||||
Emitted when the Bluetooth adapter state changes. The listener receives the new `state` string.
|
||||
|
||||
#### `event: 'discover'`
|
||||
|
||||
Emitted when a peripheral is discovered during scanning. The listener receives a `peripheral` object with `handle`, `id`, `name`, and `rssi` properties.
|
||||
|
||||
#### `event: 'connect'`
|
||||
|
||||
Emitted when a connection to a peripheral is established. The listener receives a `Peripheral` instance.
|
||||
|
||||
#### `event: 'disconnect'`
|
||||
|
||||
Emitted when a peripheral disconnects. The listener receives the `peripheral` and an optional `error`.
|
||||
|
||||
#### `event: 'connectFail'`
|
||||
|
||||
Emitted when a connection attempt fails. The listener receives the peripheral `id` and an `error`.
|
||||
|
||||
#### `event: 'scanFail'`
|
||||
|
||||
Emitted when scanning fails. The listener receives the `errorCode`.
|
||||
|
||||
#### `Central.SCAN_MODE_OPPORTUNISTIC`
|
||||
|
||||
#### `Central.SCAN_MODE_LOW_POWER`
|
||||
|
||||
#### `Central.SCAN_MODE_BALANCED`
|
||||
|
||||
#### `Central.SCAN_MODE_LOW_LATENCY`
|
||||
|
||||
Scan mode constants for use with `central.startScan()`.
|
||||
|
||||
#### `const peripheral = new Peripheral(peripheralHandle[, opts])`
|
||||
|
||||
Create a new peripheral instance. Typically obtained via the `'connect'` event on `Central` rather than constructed directly.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
opts = {
|
||||
connectHandle: null,
|
||||
id: null,
|
||||
name: null
|
||||
}
|
||||
```
|
||||
|
||||
#### `peripheral.id`
|
||||
|
||||
The unique identifier of the peripheral.
|
||||
|
||||
#### `peripheral.name`
|
||||
|
||||
The advertised name of the peripheral, or `null` if unavailable.
|
||||
|
||||
#### `peripheral.discoverServices()`
|
||||
|
||||
Discover services offered by the peripheral. Results are emitted via the `'servicesDiscover'` event.
|
||||
|
||||
#### `peripheral.discoverCharacteristics(service)`
|
||||
|
||||
Discover characteristics for the given `service`. Results are emitted via the `'characteristicsDiscover'` event.
|
||||
|
||||
#### `peripheral.read(characteristic)`
|
||||
|
||||
Read the value of
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,163 @@
|
||||
# bare-bluetooth-apple
|
||||
|
||||
**Package**: `bare-bluetooth-apple` · **Version**: v0.1.2 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
CoreBluetooth bindings for Bare.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bare-bluetooth-apple](https://github.com/holepunchto/bare-bluetooth-apple)
|
||||
- Local mirror: `holepunchto_repos/bare-bluetooth-apple`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bare-bluetooth-apple
|
||||
|
||||
CoreBluetooth bindings for Bare. Provides BLE central and peripheral roles, GATT services and characteristics, and L2CAP channels on Apple platforms.
|
||||
|
||||
```
|
||||
npm i bare-bluetooth-apple
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const bluetooth = require('bare-bluetooth-apple')
|
||||
|
||||
const server = new bluetooth.Server()
|
||||
|
||||
server.on('stateChange', (state) => {
|
||||
if (state !== 'poweredOn') return
|
||||
|
||||
const char = new bluetooth.Characteristic('01230001-0000-1000-8000-00805F9B34FB', {
|
||||
write: true,
|
||||
notify: true
|
||||
})
|
||||
|
||||
const service = new bluetooth.Service('01230000-0000-1000-8000-00805F9B34FB', [char])
|
||||
server.addService(service)
|
||||
})
|
||||
|
||||
server.on('serviceAdd', (uuid, error) => {
|
||||
if (error) return
|
||||
|
||||
server.startAdvertising({
|
||||
name: 'MyDevice',
|
||||
serviceUUIDs: ['01230000-0000-1000-8000-00805F9B34FB']
|
||||
})
|
||||
})
|
||||
|
||||
server.on('writeRequest', (requests) => {
|
||||
// Handle incoming write requests
|
||||
server.respondToRequest(requests[0], bluetooth.Server.ATT_SUCCESS, null)
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const central = new Central()`
|
||||
|
||||
Create a new BLE central manager. The central scans for and connects to peripherals.
|
||||
|
||||
#### `central.state`
|
||||
|
||||
The current Bluetooth state. One of `'unknown'`, `'resetting'`, `'unsupported'`, `'unauthorized'`, `'poweredOff'`, or `'poweredOn'`.
|
||||
|
||||
#### `central.startScan([serviceUUIDs])`
|
||||
|
||||
Start scanning for peripherals. If `serviceUUIDs` is provided, only peripherals advertising those services will be discovered.
|
||||
|
||||
#### `central.stopScan()`
|
||||
|
||||
Stop scanning for peripherals.
|
||||
|
||||
#### `central.connect(peripheral)`
|
||||
|
||||
Connect to a discovered `peripheral`.
|
||||
|
||||
#### `central.disconnect(peripheral)`
|
||||
|
||||
Disconnect from a connected `peripheral`.
|
||||
|
||||
#### `central.destroy()`
|
||||
|
||||
Destroy the central manager and release all resources.
|
||||
|
||||
#### `event: 'stateChange'`
|
||||
|
||||
Emitted with `state` when the Bluetooth state changes.
|
||||
|
||||
#### `event: 'discover'`
|
||||
|
||||
Emitted with `peripheral` when a peripheral is discovered during scanning. The `peripheral` object has `handle`, `id`, `name`, and `rssi` properties.
|
||||
|
||||
#### `event: 'connect'`
|
||||
|
||||
Emitted with `peripheral` when a connection to a peripheral is established. The `peripheral` is a `Peripheral` instance.
|
||||
|
||||
#### `event: 'disconnect'`
|
||||
|
||||
Emitted with `peripheral` and `error` when a peripheral disconnects.
|
||||
|
||||
#### `event: 'connectFail'`
|
||||
|
||||
Emitted with `id` and `error` when a connection attempt fails.
|
||||
|
||||
#### `const server = new Server()`
|
||||
|
||||
Create a new BLE peripheral manager (server). The server advertises services and handles read/write requests from centrals.
|
||||
|
||||
#### `server.state`
|
||||
|
||||
The current Bluetooth state. One of `'unknown'`, `'resetting'`, `'unsupported'`, `'unauthorized'`, `'poweredOff'`, or `'poweredOn'`.
|
||||
|
||||
#### `server.addService(service)`
|
||||
|
||||
Add a `service` to the server. The service and its characteristics will be registered with the system.
|
||||
|
||||
#### `server.startAdvertising([options])`
|
||||
|
||||
Start advertising the server.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
name: null,
|
||||
serviceUUIDs: null
|
||||
}
|
||||
```
|
||||
|
||||
#### `server.stopAdvertising()`
|
||||
|
||||
Stop advertising.
|
||||
|
||||
#### `server.respondToRequest(request, result[, data])`
|
||||
|
||||
Respond to a read or write `request` with the given ATT `result` code. Optionally include `data` for read responses.
|
||||
|
||||
#### `server.updateValue(characteristic, data)`
|
||||
|
||||
Update the value of a `characteristic` and notify subscribed centrals. Returns `true` if the update was sent successfully.
|
||||
|
||||
#### `server.publishChannel([options])`
|
||||
|
||||
Publish an L2CAP channel.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
encrypted: false
|
||||
}
|
||||
```
|
||||
|
||||
#### `server.unpublishCha
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,45 @@
|
||||
# bare-exif
|
||||
|
||||
**Package**: `bare-exif` · **Version**: v1.0.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
EXIF support for Bare.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bare-exif](https://github.com/holepunchto/bare-exif)
|
||||
- Local mirror: `holepunchto_repos/bare-exif`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bare-exif
|
||||
|
||||
EXIF support for Bare.
|
||||
|
||||
```
|
||||
npm i bare-exif
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const exif = require('bare-exif')
|
||||
|
||||
const image = require('./my-image.jpg', { with: { type: 'binary' } })
|
||||
|
||||
const data = new exif.Data(image)
|
||||
|
||||
const orientation = data.entry(exif.constants.tags.ORIENTATION)
|
||||
|
||||
orientation.read() // 1 (raw value)
|
||||
orientation.value() // Top-left (human readable string)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,20 @@
|
||||
# bare-rpc-swift
|
||||
|
||||
**Package**: `bare-rpc-swift` · **Version**: version n/a · **License**: see repository
|
||||
|
||||
## Summary
|
||||
|
||||
Holepunch ecosystem component.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bare-rpc-swift](https://github.com/holepunchto/bare-rpc-swift)
|
||||
- Local mirror: `holepunchto_repos/bare-rpc-swift`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
_No README.md in clone; see upstream repository._
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,4 +1,6 @@
|
||||
# bare-runtime - Prebuilt Bare Binaries
|
||||
# bare-runtime v1.28.4 - Prebuilt Bare Binaries
|
||||
|
||||
**Current npm version**: 1.28.4.
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# bare-stdio
|
||||
|
||||
**Package**: `bare-stdio` · **Version**: v1.0.2 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Standard input/output streams for Bare.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bare-stdio](https://github.com/holepunchto/bare-stdio)
|
||||
- Local mirror: `holepunchto_repos/bare-stdio`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bare-stdio
|
||||
|
||||
Standard input/output streams for Bare.
|
||||
|
||||
```
|
||||
npm i bare-stdio
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const stdio = require('bare-stdio')
|
||||
|
||||
// Write to stdout
|
||||
stdio.out.write('Hello, World!\n')
|
||||
|
||||
// Write to stderr
|
||||
stdio.err.write('An error occurred\n')
|
||||
|
||||
// Read from stdin
|
||||
stdio.in.on('data', (data) => {
|
||||
console.log('Received:', data.toString())
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `stdio.in`
|
||||
|
||||
A readable stream for standard input (`fd 0`). Returns a `bare-tty` `ReadStream` if stdin is a terminal, a `bare-pipe` `Pipe` if it's a pipe, otherwise a `bare-fs` `ReadStream`.
|
||||
|
||||
#### `stdio.out`
|
||||
|
||||
A writable stream for standard output (`fd 1`). Returns a `bare-tty` `WriteStream` if stdout is a terminal, a `bare-pipe` `Pipe` if it's a pipe, otherwise a `bare-fs` `WriteStream`.
|
||||
|
||||
#### `stdio.err`
|
||||
|
||||
A writable stream for standard error (`fd 2`). Returns a `bare-tty` `WriteStream` if stderr is a terminal, a `bare-pipe` `Pipe` if it's a pipe, otherwise a `bare-fs` `WriteStream`.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,42 @@
|
||||
# bare-tpl
|
||||
|
||||
**Package**: `bare-tpl` · **Version**: v1.0.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Simple template string based templating for Bare.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bare-tpl](https://github.com/holepunchto/bare-tpl)
|
||||
- Local mirror: `holepunchto_repos/bare-tpl`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bare-tpl
|
||||
|
||||
Simple template string based templating for Bare.
|
||||
|
||||
> [!CAUTION]
|
||||
> Templates support arbitrary JavaScript execution and must only be rendered from trusted input.
|
||||
|
||||
```
|
||||
npm i bare-tpl
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const tpl = require('bare-tpl')
|
||||
|
||||
tpl.render('${hello} world!', { hello: 'Howdy' })
|
||||
// Howdy world!
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,81 @@
|
||||
# safe-sodium-buffer
|
||||
|
||||
**Package**: `safe-sodium-buffer` · **Version**: v0.1.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
A secure memory management class for sodium-native with automatic resource cleanup.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [safe-sodium-buffer](https://github.com/holepunchto/safe-sodium-buffer)
|
||||
- Local mirror: `holepunchto_repos/safe-sodium-buffer`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# safe-sodium-buffer
|
||||
|
||||
A secure memory management class for sodium-native for automatic resource cleanup.
|
||||
|
||||
## Usage
|
||||
|
||||
### Automatic cleanup with `using`
|
||||
|
||||
```javascript
|
||||
const SafeBuffer = require('safe-sodium-buffer')
|
||||
|
||||
{
|
||||
using safeBuffer = new SafeBuffer(32)
|
||||
safeBuffer.fill(0x42)
|
||||
safeBuffer.fill(0xff, 1)
|
||||
}
|
||||
```
|
||||
|
||||
### Manual cleanup
|
||||
|
||||
```javascript
|
||||
const sb = new SafeBuffer(32)
|
||||
sb.fill(0x42)
|
||||
|
||||
sb.destroy()
|
||||
```
|
||||
|
||||
### Example integration
|
||||
|
||||
```javascript
|
||||
{
|
||||
using key = new SafeBuffer(32)
|
||||
using nonce = new SafeBuffer(24)
|
||||
|
||||
sodium.randombytes_buf(key.buffer)
|
||||
sodium.randombytes_buf(nonce.buffer)
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
### Constructor
|
||||
|
||||
- `new SafeBuffer(size)` - Allocates `size` bytes of secure memory
|
||||
- `SafeBuffer.from(buffer)` - Allocates a buffer from another one
|
||||
|
||||
### Properties
|
||||
|
||||
- `buffer` - The allocated Buffer (null if size is 0 or after destroy)
|
||||
- `size` - The allocated size in bytes
|
||||
- `destroyed` - Boolean indicating if memory has been freed
|
||||
|
||||
### Methods
|
||||
|
||||
- `destroy()` - Manually free and zero the memory
|
||||
- `[Symbol.dispose]()` - Automatic cleanup method (called by `using`)
|
||||
|
||||
`SafeBuffer` will expose all classic buffer methods: `compare`, `copy`, `fill`...
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,4 +1,6 @@
|
||||
# compact-encoding - Compact Binary Encoding
|
||||
# compact-encoding v2.19.2 - Compact Binary Encoding
|
||||
|
||||
**Current npm version**: 2.19.2.
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# hyperschema-swift
|
||||
|
||||
**Package**: `hyperschema-swift` · **Version**: v0.1.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Swift code generation for Hyperschema.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [hyperschema-swift](https://github.com/holepunchto/hyperschema-swift)
|
||||
- Local mirror: `holepunchto_repos/hyperschema-swift`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# hyperschema-swift
|
||||
|
||||
Swift code generation for [Hyperschema](https://github.com/holepunchto/hyperschema). Transforms schema definitions into Swift structs with binary codec conformance using <https://github.com/holepunchto/compact-encoding-swift>.
|
||||
|
||||
```
|
||||
npm i hyperschema-swift
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const SwiftHyperschema = require('hyperschema-swift')
|
||||
const Hyperschema = require('hyperschema')
|
||||
|
||||
const schema = Hyperschema.from('./spec')
|
||||
|
||||
// Get generated Swift source as a string
|
||||
const swift = new SwiftHyperschema(schema)
|
||||
const code = swift.toCode()
|
||||
|
||||
// Or write a complete Swift package to disk
|
||||
SwiftHyperschema.toDisk(schema, './output')
|
||||
```
|
||||
|
||||
`toDisk` writes a ready-to-build Swift package:
|
||||
|
||||
```
|
||||
output/
|
||||
Package.swift
|
||||
Sources/Schema.swift
|
||||
schema.json
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,129 @@
|
||||
# hello-pear-electron
|
||||
|
||||
**Package**: `hello-pear-electron` · **Version**: v1.0.0 · **License**: see repository
|
||||
|
||||
## Summary
|
||||
|
||||
Holepunch ecosystem component.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [hello-pear-electron](https://github.com/holepunchto/hello-pear-electron)
|
||||
- Local mirror: `holepunchto_repos/hello-pear-electron`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# hello-pear-electron <a name="hello-pear-electron"></a>
|
||||
|
||||
> Pear Hello World for Electron with `pear-runtime`
|
||||
|
||||
End-to-end boilerplate for embedding [pear-runtime][pear-runtime] into [Electron][electron] apps and deploying peer-to-peer application updates.
|
||||
|
||||
- Peer-to-Peer Over-the-Air updates with update-restart
|
||||
- Embedded [bare][bare] runtime workers
|
||||
- Application storage management
|
||||
- Staged deployment pipeline with multisig production releases
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [OS Support](#os-support)
|
||||
- [Requirements](#requirements)
|
||||
- [Terminology](#terminology)
|
||||
- [Development](#development)
|
||||
- [Install](#install)
|
||||
- [Start](#start)
|
||||
- [Architecture](#architecture)
|
||||
- [Updates](#updates)
|
||||
- [Storage](#storage)
|
||||
- [Workers](#workers)
|
||||
- [Peer-to-Peer Deployments](#deployments)
|
||||
- [Deployment Layers](#deployment-layers)
|
||||
- [Release Cycle](#release-cycle)
|
||||
- [Foundational Steps](#foundational-steps)
|
||||
- [0. Touch and Seed](#touch-and-seed)
|
||||
- [1. Set upgrade link](#set-upgrade-link)
|
||||
- [2. Version](#version)
|
||||
- [3. Make Distributables](#make-distributables)
|
||||
- [4. Build Deployment Directory](#build-deploy-directory)
|
||||
- [5. Stage](#stage)
|
||||
- [6. Provision](#provision)
|
||||
- [7. Multisig](#multisig)
|
||||
- [Practices](#practices)
|
||||
- [Release Lines](#release-lines)
|
||||
- [Release Line Builds](#release-line-builds)
|
||||
- [Custom Builds](#custom-builds)
|
||||
- [Scripts](#scripts)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## OS Support <a name="os-support"></a>
|
||||
|
||||
- macOS
|
||||
- Linux
|
||||
- Windows
|
||||
|
||||
## Requirements <a name="requirements"></a>
|
||||
|
||||
- `npm` via [Node.js][nodejs]
|
||||
- [`pear`][pear-docs] - `npx pear`
|
||||
|
||||
## Terminology <a name="terminology"></a>
|
||||
|
||||
- **OTA** - Over-the-Air. Data delivery without manual intervention
|
||||
- **OTA Updates** - Direct software updates to running applications without manual reinstallation
|
||||
- **P2P** - Peer-to-Peer. Direct point-to-point communication between machines/devices without central servers
|
||||
- **application drive** - the [Hyperdrive][hyperdrive] behind a Pear application
|
||||
- **deployment folder** - the build directory output by `pear-build` which is then staged
|
||||
- **multisig** - a co-signing protocol requiring a quorum of signers before writes can be committed. This cryptographically binds project integrity to collective sign-off
|
||||
- **pear link** - a [link format][pear-link-format] for addressing peer-to-peer applications
|
||||
- **quorum** - the minimum number of signers needed to commit a multisig write
|
||||
- **release lines** - parallel deployment streams at different stability levels
|
||||
- **seeding** - exposing a drive to peers for discovery and download
|
||||
- **vendor signing** - signing distributables with OS-level certificates so they run on other machines without quarantine e.g. Apple notarization, Windows code signing
|
||||
- **versioned link** - a pear link of the form `pear://<fork>.<length>.<key>` where fork, length and key correspond to [core.fork][hypercore-fork], [core.length][hypercore-length], and [core.key][hypercore-key] of the [Hypercore][hypercore] behind the [Hyperdrive][hyperdrive] behind the Pear application
|
||||
|
||||
## Development <a name="development"></a>
|
||||
|
||||
### Install <a name="install"></a>
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Start <a name="start"></a>
|
||||
|
||||
Start app in development mode:
|
||||
|
||||
```sh
|
||||
npm start
|
||||
```
|
||||
|
||||
When running locally, updates are turned off to avoid the built application being swapped from local development when there is an update.
|
||||
|
||||
To enable updates for testing update flow in local development use
|
||||
|
||||
```sh
|
||||
npm start -- --u
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## Recent changelog (excerpt)
|
||||
|
||||
# Hello - Your Changelog Here
|
||||
|
||||
## v1.0.0
|
||||
|
||||
### Features
|
||||
|
||||
- example feature
|
||||
|
||||
### Fixes
|
||||
|
||||
- example fix
|
||||
|
||||
### Improvements
|
||||
|
||||
- example improvement
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,6 +1,6 @@
|
||||
# hyperblobs
|
||||
# hyperblobs v2.11.1
|
||||
|
||||
Blob store for Hypercore.
|
||||
**Current npm version**: 2.11.1. Blob store for Hypercore.
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
# Hypercore v11.26.0 - Append-Only Distributed Log
|
||||
# Hypercore v11.28.1 - Append-Only Distributed Log
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -98,6 +98,10 @@ swarm.join(core.discoveryKey)
|
||||
- Event sourcing
|
||||
|
||||
**Docs**: [Pears.com/hypercore](https://docs.pears.com/building-blocks/hypercore)
|
||||
**Source**: [github.com/holepunchto/hypercore](https://github.com/holepunchto/hypercore) (11.26.0)
|
||||
**Source**: [github.com/holepunchto/hypercore](https://github.com/holepunchto/hypercore) (11.28.1)
|
||||
|
||||
## Recent upstream changes (KB sync)
|
||||
|
||||
- **11.28.x**: Storage writes batching in internal overwrite paths; publish workflow for releases; **verify Ed25519 signature before persisting commits** (tightens replication safety). See upstream `CHANGELOG.md` / git history for full detail.
|
||||
|
||||
~4500 chars added.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# HyperDHT - Kademlia DHT Engine
|
||||
# HyperDHT v6.30.0 - Kademlia DHT Engine
|
||||
|
||||
**Current npm version**: 6.30.0 ([holepunchto/hyperdht](https://github.com/holepunchto/hyperdht)).
|
||||
|
||||
## Deep Dive Expansion
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Hyperdrive v13.3.0 - Distributed P2P Filesystem Deep Dive
|
||||
# Hyperdrive v13.3.2 - Distributed P2P Filesystem Deep Dive
|
||||
|
||||
## Enhanced Overview (Expansion)
|
||||
|
||||
Hyperdrive builds a **mutable, versioned POSIX-like FS** on Hypercore primitives. Real-time collab, offline sync, blob dedup. Used in Pear/Keet for app bundles/fileshare.
|
||||
|
||||
**Stats**: 13.3.0, deps hyperbee^2.11/hyperblobs^2.9/hypercore^11, mirror-drive, streamx.
|
||||
**Stats**: 13.3.2, deps hyperbee^2.11/hyperblobs^2.9/hypercore^11, mirror-drive, streamx.
|
||||
|
||||
**Evolution**: v10+ truncate, v13 SMALL_WANTS/parallel dl.
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
# hypermininet
|
||||
|
||||
**Package**: `hypermininet` · **Version**: v1.5.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
A high-level wrapper around around mininet for easy swarm testing.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [hypermininet](https://github.com/holepunchto/hypermininet)
|
||||
- Local mirror: `holepunchto_repos/hypermininet`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# Hypermininet
|
||||
|
||||
A high-level wrapper around [mininet](https://github.com/mafintosh/mininet) for testing [Hyperswarm](https://github.com/holepunchto/hyperswarm) and [HyperDHT](https://github.com/holepunchto/hyperdht) applications in simulated network conditions.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install hypermininet
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const Hypermininet = require('hypermininet')
|
||||
|
||||
const hypermininet = new Hypermininet({
|
||||
debug: true,
|
||||
mininet: { clean: true },
|
||||
network: {
|
||||
hosts: 10,
|
||||
link: {
|
||||
bandwidth: 1, // 1 Mbit link
|
||||
delay: '100ms', // 100ms latency
|
||||
loss: 10, // 10% packet loss
|
||||
htb: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await hypermininet.ready()
|
||||
|
||||
// Define a function to run on hosts
|
||||
const helloWorld = hypermininet.add(({ data, bootstrap, controller }) => {
|
||||
const Hyperswarm = require('hyperswarm')
|
||||
const swarm = new Hyperswarm({ bootstrap })
|
||||
|
||||
console.log('Running on host with data:', data)
|
||||
|
||||
controller.on('data', (msg) => {
|
||||
console.log('Received:', msg)
|
||||
})
|
||||
})
|
||||
|
||||
// Boot the hypermininet (starts the DHT bootstrapper)
|
||||
await hypermininet.boot(async () => {
|
||||
for (const host of hypermininet.hosts) {
|
||||
await helloWorld(host, { hello: 'world' })
|
||||
}
|
||||
})
|
||||
|
||||
// Cleanup
|
||||
await hypermininet.close()
|
||||
```
|
||||
|
||||
### Internet access
|
||||
|
||||
Your switch (which the hosts `link` to) can be given internet access automatically.
|
||||
|
||||
```js
|
||||
const Hypermininet = require('hypermininet')
|
||||
|
||||
const hypermininet = new Hypermininet({
|
||||
debug: true,
|
||||
mininet: { clean: true, internet: true },
|
||||
network: {
|
||||
hosts: 10,
|
||||
link: {
|
||||
bandwidth: 1, // 1 Mbit link
|
||||
delay: '100ms', // 100ms latency
|
||||
loss: 10, // 10% packet loss
|
||||
htb: true
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Different runtime for hosts
|
||||
|
||||
Hosts can be run with different runtimes by passing `exec: <your executable>`.
|
||||
This will be used when running JS on the hosts, so it must still be compatible.
|
||||
|
||||
```js
|
||||
const Hypermininet = require('hypermininet')
|
||||
|
||||
const hypermininet = new Hypermininet({
|
||||
debug: true,
|
||||
mininet: { clean: true, internet: true },
|
||||
network: {
|
||||
exec: 'bare',
|
||||
hosts: 10,
|
||||
link: {
|
||||
bandwidth: 1, // 1 Mbit link
|
||||
delay: '100ms', // 100ms latency
|
||||
loss: 10, // 10% packet loss
|
||||
htb: true
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Mixed network configs
|
||||
|
||||
As well as creating multiple hosts with a single `link` config (controlling speed, delay etc.); this can also be controlled per host.
|
||||
|
||||
The example will create 3 hosts, with 3 different preset configs used
|
||||
|
||||
```js
|
||||
const Hypermininet = require('hypermininet')
|
||||
|
||||
const hypermininet = new Hypermininet({
|
||||
debug: true,
|
||||
mininet: { clean: true },
|
||||
network: {
|
||||
hosts: [Hypermininet.NetworkPotato, Hypermininet.NetworkOK, Hypermininet.Network3GRural]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `new Hypermininet(opts)`
|
||||
|
||||
Create a new Hypermininet instance.
|
||||
|
||||
Options:
|
||||
|
||||
- `debug` (boolean): Enable debug logging. Default: `false`
|
||||
- `mininet` (object): Options passed to the underlying Mininet instance
|
||||
- `clean` (boolean): Clean up existing Mininet state on start
|
||||
- `network` (object): Network configuration
|
||||
- `hosts` (number): Number of hosts to create. Default: `10`
|
||||
- `link` (object): Link configuration applied to all host connections
|
||||
- `bandwidth` (number): Bandwidth in Mbit/s
|
||||
- `delay` (string): Latency (e.g., `'100ms'`)
|
||||
- `loss` (number): Packet loss percentage
|
||||
- `htb` (boolean): Use HTB qdisc
|
||||
- `bootstrap` (object): Bootstrap node configuration
|
||||
- `port` (number): Port for the DHT bootstrapper. Default: `49737`
|
||||
|
||||
### `await hypermininet.ready(
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,6 +1,6 @@
|
||||
# hyperschema
|
||||
# hyperschema v1.20.1
|
||||
|
||||
Declarative, versioned binary encoding definitions with code generation.
|
||||
**Current npm version**: 1.20.1. Declarative, versioned binary encoding definitions with code generation.
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Hyperswarm - Core Swarm Library (holepunchto/hyperswarm)
|
||||
|
||||
Latest version: **4.16.0** (main branch)
|
||||
Latest version: **4.17.0** (see `package.json` in [holepunchto/hyperswarm](https://github.com/holepunchto/hyperswarm))
|
||||
|
||||
GitHub: [holepunchto/hyperswarm](https://github.com/holepunchto/hyperswarm) (~1.2k stars)
|
||||
Docs: [docs.pears.com/building-blocks/hyperswarm](https://docs.pears.com/building-blocks/hyperswarm)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# libmqjs
|
||||
|
||||
**Package**: `libmqjs` · **Version**: version n/a · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Holepunch ecosystem component.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [libmqjs](https://github.com/holepunchto/libmqjs)
|
||||
- Local mirror: `holepunchto_repos/libmqjs`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# libmqjs
|
||||
|
||||
ABI compatible replacement for <https://github.com/holepunchto/libjs> built on Micro QuickJS. Useful for IoT, embedded, or otherwise constrained systems where the requirements of V8 can become problematic.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,5 +1,7 @@
|
||||
# rocksdb-native - RocksDB Bindings for JavaScript
|
||||
|
||||
**Canonical KB article** for the `[holepunchto/rocksdb-native](https://github.com/holepunchto/rocksdb-native)` package. (A legacy duplicate stub under `modules/storage/rocksdb.md` was removed; use this file.)
|
||||
|
||||
## Overview
|
||||
|
||||
rocksdb-native provides JavaScript bindings for RocksDB, Facebook's high-performance embedded database. It offers a fast key-value store with advanced features like column families, snapshots, and atomic transactions.
|
||||
@@ -50,6 +52,8 @@ graph TB
|
||||
ROCKS --> WAL
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
@@ -98,12 +102,14 @@ Main database class.
|
||||
Open or create a database.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `path` (string): Database directory path
|
||||
- `options` (object, optional):
|
||||
- `createIfMissing` (boolean): Create if doesn't exist (default: true)
|
||||
- `errorIfExists` (boolean): Error if exists (default: false)
|
||||
|
||||
**Example:**
|
||||
|
||||
```js
|
||||
const db = new RocksDB('./mydb', {
|
||||
createIfMissing: true
|
||||
@@ -123,6 +129,7 @@ Create a write batch.
|
||||
Add a put operation to the batch.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `key` (string | Buffer): Key
|
||||
- `value` (string | Buffer): Value
|
||||
|
||||
@@ -133,6 +140,7 @@ Add a put operation to the batch.
|
||||
Add a delete operation to the batch.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `key` (string | Buffer): Key to delete
|
||||
|
||||
**Returns:** WriteBatch (for chaining)
|
||||
@@ -141,7 +149,7 @@ Add a delete operation to the batch.
|
||||
|
||||
Execute all operations in the batch.
|
||||
|
||||
**Returns:** Promise<void>
|
||||
**Returns:** Promise
|
||||
|
||||
### Read Snapshot
|
||||
|
||||
@@ -156,6 +164,7 @@ Create a read snapshot.
|
||||
Get a value from the snapshot.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `key` (string | Buffer): Key to look up
|
||||
|
||||
**Returns:** Promise<Buffer | null>
|
||||
@@ -543,4 +552,5 @@ const db = new RocksDB('./bee-storage')
|
||||
Apache-2.0
|
||||
|
||||
---
|
||||
**Module Type**: Storage | **Ecosystem Role**: Database Engine | **Dependencies**: librocksdb
|
||||
|
||||
**Module Type**: Storage | **Ecosystem Role**: Database Engine | **Dependencies**: librocksdb
|
||||
+19
@@ -1,5 +1,20 @@
|
||||
# hyperdht-address
|
||||
|
||||
**Package**: `hyperdht-address` · **Version**: v1.0.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
hyperdht-address.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [hyperdht-address](https://github.com/holepunchto/hyperdht-address)
|
||||
- Local mirror: `holepunchto_repos/hyperdht-address`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# hyperdht-address
|
||||
|
||||
Encode and decode HyperDHT addresses.
|
||||
|
||||
## Install
|
||||
@@ -32,3 +47,7 @@ Decode a buffer into an address object with `key` (Buffer) and `nodes` (array of
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,110 @@
|
||||
# _pear-build
|
||||
|
||||
**Package**: `pear-build` · **Version**: v1.1.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Create project deployment folder.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [_pear-build](https://github.com/holepunchto/_pear-build)
|
||||
- Local mirror: `holepunchto_repos/_pear-build`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# pear-build
|
||||
|
||||
> Build appling for a Pear application
|
||||
|
||||
```
|
||||
npm install -g pear-build
|
||||
```
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
- Linux: `linux-arm64`, `linux-x64`
|
||||
- macOS: `darwin-arm64`, `darwin-x64`
|
||||
- Windows: `win32-arm64`, `win32-x64`
|
||||
- iOS: `ios-arm64`, `ios-arm64-simulator`, `ios-x64-simulator`
|
||||
- Android: `android-arm64`
|
||||
|
||||
## Usage
|
||||
|
||||
Create a build dir outside the project root.
|
||||
|
||||
```bash
|
||||
pear-build \
|
||||
--package=./my-app/package.json \
|
||||
--darwin-arm64-app ./my-app/MyApp-darwin-arm64/MyApp.app \
|
||||
--linux-x64-app=./my-app/MyApp-linux-x64/MyApp.AppImage \
|
||||
--target=./my-build
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```bash
|
||||
node bin.js \
|
||||
--package ./test/fixtures/hello-pear-electron/package.json \
|
||||
--darwin-arm64-app ./test/fixtures/hello-pear-electron/out/HelloPear-darwin-arm64/HelloPear.app \
|
||||
--darwin-x64-app ./test/fixtures/hello-pear-electron/out/HelloPear-darwin-x64/HelloPear.app \
|
||||
--linux-arm64-app ./test/fixtures/hello-pear-electron/out/HelloPear-linux-arm64/HelloPear.AppImage \
|
||||
--linux-x64-app ./test/fixtures/hello-pear-electron/out/HelloPear-linux-x64/HelloPear.AppImage \
|
||||
--win32-x64-app ./test/fixtures/hello-pear-electron/out/HelloPear-win32-x64/HelloPear.msix \
|
||||
--win32-arm64-app ./test/fixtures/hello-pear-electron/out/HelloPear-win32-arm64/HelloPear.msix \
|
||||
--ios-arm64 ./test/fixtures/hello-pear-react-native/ota/ios/HelloPear \
|
||||
--ios-arm64-simulator ./test/fixtures/hello-pear-react-native/ota/ios/HelloPear \
|
||||
--ios-x64-simulator ./test/fixtures/hello-pear-react-native/ota/ios/HelloPear \
|
||||
--android-arm64 ./test/fixtures/hello-pear-react-native/ota/android/HelloPear \
|
||||
--target ./my-build
|
||||
```
|
||||
|
||||
`$ tree my-build/`
|
||||
|
||||
```bash
|
||||
my-build
|
||||
├── by-arch
|
||||
│ ├── android-arm64
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear
|
||||
│ │ └── app.bundle
|
||||
│ ├── darwin-arm64
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear.app
|
||||
│ ├── darwin-x64
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear.app
|
||||
│ ├── ios-arm64
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear
|
||||
│ │ └── app.bundle
|
||||
│ ├── ios-arm64-simulator
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear
|
||||
│ │ └── app.bundle
|
||||
│ ├── ios-x64-simulator
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear
|
||||
│ │ └── app.bundle
|
||||
│ ├── linux-arm64
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear.AppImage
|
||||
│ ├── linux-x64
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear.AppImage
|
||||
│ ├── win32-arm64
|
||||
│ │ └── app
|
||||
│ │ └── HelloPear.msix
|
||||
│ └── win32-x64
|
||||
│ └── app
|
||||
│ └── HelloPear.msix
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,37 @@
|
||||
# bare-sidecar-bundle
|
||||
|
||||
**Package**: `bare-sidecar-bundle` · **Version**: v1.0.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Bare bundler optimised for sidecars to be used in pear-runtime.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bare-sidecar-bundle](https://github.com/holepunchto/bare-sidecar-bundle)
|
||||
- Local mirror: `holepunchto_repos/bare-sidecar-bundle`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bare-sidecar-bundle
|
||||
|
||||
Bare bundler optimised for sidecars to be used in pear-runtime
|
||||
|
||||
```
|
||||
npm install -g bare-sidecar-bundle
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
// bundle index.mjs, put all addons in ./prebuilds/{hash}, write to index.bundle
|
||||
bare-sidecar-bundler ./index.mjs ./index.bundle
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,141 @@
|
||||
# bundlebee-cli
|
||||
|
||||
**Package**: `bundlebee-cli` · **Version**: v1.0.4 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Manage, push, sign and seed your Bundles with Bees!.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bundlebee-cli](https://github.com/holepunchto/bundlebee-cli)
|
||||
- Local mirror: `holepunchto_repos/bundlebee-cli`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bundlebee
|
||||
|
||||
Bundle JavaScript modules into a [Hyperbee](https://github.com/holepunchto/hyperbee2) for peer-to-peer sharing.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install -g bundlebee
|
||||
```
|
||||
|
||||
## Publishing modules with Bundlebee
|
||||
|
||||
Bundlebee replaces `npm publish` with P2P distribution. You bundle your module into a Hyperbee, seed it on the swarm, and consumers import it by link — no registry required.
|
||||
|
||||
### Release flow
|
||||
|
||||
#### 1. Bundle your module
|
||||
|
||||
```sh
|
||||
bundlebee store . index.js
|
||||
```
|
||||
|
||||
This traverses `.`, resolves its dependency tree from `index.js` (if no entrypoint, `index.js` will be used), and stores everything into a local Hyperbee. On completion it prints the import link directly:
|
||||
|
||||
```
|
||||
✔ Added 14 file(s):
|
||||
/index.js
|
||||
/lib/utils.js
|
||||
...
|
||||
|
||||
Key: bundle+pear://0.7.zgqe3s3i7dcb9tirqu8zb5tb9c7xkbs165eyiaxy1ep7xhqboozy/index.js
|
||||
Length: 7
|
||||
```
|
||||
|
||||
That `Key:` line is your import link — copy it and share it with consumers.
|
||||
|
||||
Optionally: Use `--abi` to tag each release. The ABI must increment with each publish — think of it as your version number. Append `?abi=<n>` to the link so consumers resolve the correct checkout.
|
||||
|
||||
If ABI is provided instead of length, it has the same end effect. Except it will need to get the latest Bundlebee data; and search it to find the correct checkout point based on the ABI.
|
||||
|
||||
> **Pinning with length:** For safety, length is prefixed to the url so we can checkout the exact Bundle rather than latest:
|
||||
>
|
||||
> ```
|
||||
> bundle+pear://0.7.zgqe3s3i7dcb9tirqu8zb5tb9c7xkbs165eyiaxy1ep7xhqboozy@7/index.js?abi=1
|
||||
> ```
|
||||
|
||||
> **Note:** `--dry-run` lets you preview what would be stored and warns if your ABI isn't greater than the last one.
|
||||
|
||||
#### 2. Seed it
|
||||
|
||||
```sh
|
||||
bundlebee seed
|
||||
```
|
||||
|
||||
This joins the Hyperswarm on your bundle's discovery key so peers can replicate. Keep this running (or add blind peers to `package.json` for persistent seeding):
|
||||
|
||||
```json
|
||||
{
|
||||
"blindPeers": ["<public-key>"]
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. Import from another project
|
||||
|
||||
```js
|
||||
const Import = require('bundlebee-import')
|
||||
const Corestore = require('corestore')
|
||||
const Hyperswarm = require('hyperswarm')
|
||||
|
||||
const store = new Corestore('./reader-storage')
|
||||
const swarm = new Hyperswarm()
|
||||
swarm.on('connection', (conn) => store.replicate(conn))
|
||||
|
||||
const mod = await Import(store, 'bundle+pear://0.7.zgqe3s3i7dcb...@7/index.js', {
|
||||
swarm
|
||||
})
|
||||
|
||||
// mod is the module's exports, as if you had require()'d it
|
||||
```
|
||||
|
||||
`bundlebee-import` joins the swarm, replicates the core, resolves the ABI checkout, loads the module graph, and returns `module.exports` — then tears down the Bundlebee instance.
|
||||
|
||||
Note: swarm is optional, and can be handled manually
|
||||
|
||||
### Updating
|
||||
|
||||
To publish a new version, simply run again:
|
||||
|
||||
```sh
|
||||
bundlebee store . index.js
|
||||
```
|
||||
|
||||
Distribute the new link with the updated length or abi.
|
||||
|
||||
## Usage
|
||||
|
||||
### Store
|
||||
|
||||
Bundle a folder into a Bundlebee:
|
||||
|
||||
```
|
||||
bundlebee store ./my-project
|
||||
bundlebee store ./my-project main.js --abi 1
|
||||
bundlebee store ./my-project --include-modules
|
||||
bundlebee store ./my-project --dry-run
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
| ---------------------- | ---------------------------------------------- |
|
||||
| `--storage, -s <path>` | Corestore storage path (default: `.bundlebee`) |
|
||||
| `--abi, -a <abi>` | Store under a specific ABI |
|
||||
| `--include-modules` | Include `node_modules` (default: false) |
|
||||
| `--dry-run` | Gather files without writing |
|
||||
|
||||
### Checkout
|
||||
|
||||
Checkout files from a Bundlebee to disk:
|
||||
|
||||
```
|
||||
bundle
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,126 @@
|
||||
# bundlebee
|
||||
|
||||
**Package**: `bundlebee` · **Version**: v1.2.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
bundlebee.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [bundlebee](https://github.com/holepunchto/bundlebee)
|
||||
- Local mirror: `holepunchto_repos/bundlebee`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# bundlebee
|
||||
|
||||
Bundle modules into [Hyperbee2](https://github.com/holepunchto/hyperbee2) for P2P sharing. Based on [bare-union-bundle](https://github.com/holepunchto/bare-union-bundle) but uses a Hyperbee2 as the backing store instead of flat bundle files, enabling replication and versioned checkouts over the network.
|
||||
|
||||
```
|
||||
npm install bundlebee
|
||||
```
|
||||
|
||||
For the CLI for using this on your project see: https://github.com/holepunchto/bundlebee-cli
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const Bundlebee = require('bundlebee')
|
||||
const Corestore = require('corestore')
|
||||
|
||||
const store = new Corestore('./storage')
|
||||
const b = new Bundlebee(store)
|
||||
|
||||
// Add a module entry point
|
||||
const bundle = await b.add(new URL('file:///path/to/project/'), 'index.js')
|
||||
|
||||
// Load a module from the bee
|
||||
const mod = await b.load(new URL('file:///path/to/project/'), '/index.js')
|
||||
```
|
||||
|
||||
### Loading from existing bundle files
|
||||
|
||||
```js
|
||||
const b = await Bundlebee.require(store, './0.bundle', './1.bundle')
|
||||
```
|
||||
|
||||
### Getting existing bundles
|
||||
|
||||
```js
|
||||
const b = new Bundlebee(store, { key: myKey })
|
||||
|
||||
// get remote bundle
|
||||
const mod = await b.load(new URL('file:///path/to/project/'), '/index.js')
|
||||
|
||||
// get remote historical file using Hyperbee2 length
|
||||
const { source, resolutions } = await b1.get('/entrypoint.js', 1)
|
||||
```
|
||||
|
||||
### Checkout a specific version on init
|
||||
|
||||
```js
|
||||
const b = new Bundlebee(store, { key, length })
|
||||
|
||||
// get remote bundle
|
||||
const mod = await b.load(new URL('file:///path/to/project/'), '/index.js')
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const b = new Bundlebee(store, [opts])`
|
||||
|
||||
Create a new Bundlebee instance backed by a Hyperbee2. `store` is passed directly to the `hyperbee2` constructor. `opts` are forwarded to Hyperbee2.
|
||||
|
||||
#### `const b = await Bundlebee.require(store, ...files, [opts])`
|
||||
|
||||
Static helper that creates a Bundlebee and imports one or more `.bundle` files (from [bare-bundle](https://github.com/holepunchto/bare-bundle)) into the bee. `opts` are forwarded to the Bundlebee constructor.
|
||||
|
||||
#### `await b.ready()`
|
||||
|
||||
Wait for the underlying Hyperbee2 to be ready. This is done automatically on init and use of any async functions.
|
||||
|
||||
#### `const entry = await b.get(key, [checkout])`
|
||||
|
||||
Get a single entry by its key (the file path within the bundle). Returns `{ source, resolutions }` or `null` if not found.
|
||||
|
||||
If `checkout` is provided it is used as the Hyperbee length for a snapshot checkout.
|
||||
|
||||
#### `const bee = await b.checkout(length)`
|
||||
|
||||
Return a Hyperbee snapshot at the given `length`. If `length` is omitted, the current head is used.
|
||||
|
||||
#### `const bundle = await b.add(root, entrypoint, [opts])`
|
||||
|
||||
Traverse `entrypoint` relative to `root` (a `file://` URL) and write all discovered modules into the bee. Returns the resulting `bare-bundle` Bundle. Only changed files are written.
|
||||
|
||||
`opts` includes:
|
||||
|
||||
```js
|
||||
{
|
||||
skipModules: true // skip bundling dependencies found in `node_modules`
|
||||
}
|
||||
```
|
||||
|
||||
#### `const mod = await b.load(root, entrypoint, [checkout], [opts])`
|
||||
|
||||
Load `entrypoint` from the bee using `bare-module`. If `checkout` is provided, a snapshot at that Hyperbee length is used.
|
||||
|
||||
`opts` includes:
|
||||
|
||||
```js
|
||||
{
|
||||
cache: require.cache, // module cache
|
||||
skipModules: true // resolve node_modules from the local cache instead of the bundle
|
||||
}
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
Bundlebee uses `bare-module-traverse` to walk a module graph from an entry point, then stores each file's source and its resolution map into Hyperbee2 keyed by file path. On load, it reads all entries from the bee, wires up resolutions, and uses `bare-module` to evaluate the module graph. Becaus
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,20 @@
|
||||
# cellery-html
|
||||
|
||||
**Package**: `cellery-html` · **Version**: v1.1.12 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
cellery-html.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [cellery-html](https://github.com/holepunchto/cellery-html)
|
||||
- Local mirror: `holepunchto_repos/cellery-html`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# cellery-html
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,98 @@
|
||||
# cellery
|
||||
|
||||
**Package**: `cellery` · **Version**: v1.4.5 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
cellery.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [cellery](https://github.com/holepunchto/cellery)
|
||||
- Local mirror: `holepunchto_repos/cellery`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# Cellery
|
||||
|
||||
> **WIP** - A stream-driven cross-platform UI framework
|
||||
|
||||
Cellery is a minimal UI framework built around streams. Components called **Cells** subscribe to events and emit render instructions — no virtual DOM, no framework lock-in. Any Adapter can consume the output: HTML, TUI, native, mobile, whatever fits your use case.
|
||||
|
||||
## How it works
|
||||
|
||||
Cellery sits at the end of a pipeline. Writers (state machines, database change feeds, RPC streams) push events in, and Cells react by emitting render instructions out.
|
||||
|
||||
This publishes events to `Cellery` which you can subscribe to.
|
||||
|
||||
```js
|
||||
const { Cellery } = require('cellery')
|
||||
|
||||
pipeline(
|
||||
myWriter,
|
||||
new Transform({
|
||||
transform(status, cb) {
|
||||
this.push({ event: 'something-happened', status })
|
||||
cb()
|
||||
}
|
||||
}),
|
||||
cellery
|
||||
)
|
||||
```
|
||||
|
||||
Cells subscribe to events and re-render reactively:
|
||||
|
||||
```js
|
||||
const welcome = new Message({ id: 'welcome', value: 'Welcome', cellery })
|
||||
|
||||
welcome.sub({ event: 'login' }, (cell, { user }) => {
|
||||
cell.value = `Welcome back ${user.displayName}`
|
||||
cell.render({ id: 'messages', insert: 'beforeend' })
|
||||
})
|
||||
```
|
||||
|
||||
Or you render Cells at will, passing details how they should render:
|
||||
|
||||
```js
|
||||
const msg = new Message({ value: 'Use /join <invite> to join a room', cellery })
|
||||
msg.render({ id: 'messages', insert: 'beforeend' })
|
||||
```
|
||||
|
||||
Rendering is handled by `Adapters`. Currently these are simply called by `Cellery` to render components when components manually choose to be re-rendered. By default they pass along meta so your `adapter` can figure out what to do with them. But there's no rules, no lifecycles. Just streams of content and events for your to react to as you need.
|
||||
|
||||
## Cells
|
||||
|
||||
We're trying to keep Cells simple. A super basic set of low level components to see how much can be achieved with little.
|
||||
|
||||
| Cell | Description |
|
||||
| ----------- | ---------------------------------------- |
|
||||
| `Cell` | Base class for all components |
|
||||
| `MultiCell` | Composes multiple cells into one render |
|
||||
| `Container` | Layout wrapper with scroll and flex opts |
|
||||
| `App` | Root cell, id is always `'app'` |
|
||||
| `Text` | Inline text content |
|
||||
| `Paragraph` | Block text content |
|
||||
| `Input` | Text input, single or multiline |
|
||||
|
||||
## Decorations
|
||||
|
||||
Style primitives passed to cells — `Adapters` decide how to apply them. Just more meta for you to render with.
|
||||
|
||||
- `Color` — RGBA color, construct from hex or object
|
||||
- `Spacing` — padding/margin with `all`, `symmetric`, or `only`
|
||||
- `Border` — border width and color
|
||||
- `BoxDecoration` — wraps border (and future decoration props)
|
||||
- `Alignment` — horizontal or vertical layout direction with justify/items
|
||||
- `Size` — named size tokens: `xs`, `s`, `m`, `l`, `xl`
|
||||
|
||||
## Renderers
|
||||
|
||||
`Adapters` must implement a single `render(cell)` method and return content in whatever format they need. The framework makes no assumptions about output format.
|
||||
|
||||
## Status
|
||||
|
||||
Work in progress. API subject to change.
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,114 @@
|
||||
# make-pear-app
|
||||
|
||||
**Package**: `make-pear-app` · **Version**: version n/a · **License**: see repository
|
||||
|
||||
## Summary
|
||||
|
||||
Holepunch ecosystem component.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [make-pear-app](https://github.com/holepunchto/make-pear-app)
|
||||
- Local mirror: `holepunchto_repos/make-pear-app`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# Make Pear Apps :pear:
|
||||
|
||||
GitHub Action to build Pear apps on Linux, macOS, and Windows, with code signing and artifact upload.
|
||||
|
||||
## Inputs
|
||||
|
||||
### Build Inputs
|
||||
|
||||
| Input | Description | Required |
|
||||
|-------|------------|----------|
|
||||
| `channel` | Channel name (e.g. `preview`, `experimental`, `staging`) | Yes |
|
||||
| `upgrade_key` | Upgrade key (e.g. `pear://jj7jywoj83pswtcf5asywbm4ngro3xikgg1zcaqq3kdyhghats6o`) | No |
|
||||
|
||||
### macOS
|
||||
|
||||
| Input | Description | Required |
|
||||
|-------|------------|----------|
|
||||
| `macos_certificate_base64` | Base64 Apple distribution certificate (P12) | Required on macOS |
|
||||
| `macos_p12_password` | Password for the P12 certificate | Required on macOS |
|
||||
| `macos_codesign_identity` | Code signing identity | Required on macOS |
|
||||
| `macos_notarization_method` | Notarization method to use: `appstore_connect` or `apple_id_password` | Required on macOS |
|
||||
| `macos_apple_id` | Apple ID email for notarization | Required on macOS if `macos_notarization_method` is `apple_id_password` |
|
||||
| `macos_apple_password` | Apple app-specific password | Required on macOS if `macos_notarization_method` is `apple_id_password` |
|
||||
| `macos_apple_team_id` | Apple Developer Team ID | Required on macOS if `macos_notarization_method` is `apple_id_password` |
|
||||
| `macos_api_key_base64` | Base64-encoded App Store Connect API key (like AuthKey_ABCD123456.p8) | Required on macOS if `macos_notarization_method` is `appstore_connect` |
|
||||
| `macos_api_key_id` | 10-character alphanumeric ID string of the App Store Connect (like ABCD123456) | Required on macOS if `macos_notarization_method` is `appstore_connect` |
|
||||
| `macos_api_issuer` | UUID that identifies the API key issuer | Required on macOS if `macos_notarization_method` is `appstore_connect` |
|
||||
|
||||
### Linux
|
||||
|
||||
Linux builds require no inputs.
|
||||
|
||||
## Outputs
|
||||
|
||||
| Output | Description |
|
||||
|-------|------------|
|
||||
| `artifact-links` | Links to the uploaded artifacts from the `out/make` folder. Each file is uploaded individually and the link can be used in workflow notifications (e.g., Slack, Teams). |
|
||||
|
||||
## Usage
|
||||
|
||||
### Linux
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
artifact-links: ${{ steps.build.outputs.artifact-links }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: holepunchto/make-pear-app
|
||||
id: build
|
||||
with:
|
||||
channel: experimental
|
||||
upgrade_key: pear://jj7jywoj83pswtcf5asywbm4ngro3xikgg1zcaqq3kdyhghats6o
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
outputs:
|
||||
artifact-links: ${{ steps.build.outputs.artifact-links }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: holepunchto/make-pear-app
|
||||
id: build
|
||||
with:
|
||||
channel: preview
|
||||
macos_certificate_base64: ${{ secrets.APPLE_DISTRIBUTION_CERTIFICATE }}
|
||||
macos_p12_password: ${{ secrets.APPLE_P12_PASSWORD }}
|
||||
macos_codesign_identity: ${{ secrets.MAC_CODESIGN_IDENTITY }}
|
||||
macos_notarization_method: apple_id_password
|
||||
macos_apple_id: ${{ secrets.APPLE_ID }}
|
||||
macos_apple_password: ${{ secrets.APPLE_PASSWORD }}
|
||||
macos_apple_team_id: ${{ secrets.APPLE_TEAM_ID }}
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build-win32:
|
||||
runs-on: self-hosted
|
||||
outputs:
|
||||
artifact-links: ${{ steps.build.outputs.artifact-links }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: holepunchto/make-pear-app
|
||||
id: build
|
||||
with:
|
||||
channel: stage
|
||||
```
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 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.
|
||||
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 the legacy **`pear run`** subcommand (the **CLI** `pear run` path is **deprecated** from Pear v2.4+ in favor of **`pear-runtime`**; this package may still ship parser metadata for compatibility—see [`Pear`](../utilities/pear.md)).
|
||||
|
||||
### Key Features
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# pear-multisig-link
|
||||
|
||||
**Package**: `pear-multisig-link` · **Version**: v1.0.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Deterministic multisig link per multisig inputs.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [pear-multisig-link](https://github.com/holepunchto/pear-multisig-link)
|
||||
- Local mirror: `holepunchto_repos/pear-multisig-link`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# pear-multisig-link
|
||||
|
||||
> Deterministic multisig link per multisig inputs
|
||||
|
||||
## Usage
|
||||
|
||||
In project root with a `pear.json` file:
|
||||
|
||||
```sh
|
||||
npx pear-multisig-link
|
||||
```
|
||||
|
||||
Custom config file:
|
||||
|
||||
```sh
|
||||
npx pear-multisig-link --config path/to/pear.json
|
||||
```
|
||||
|
||||
Passing in arguments:
|
||||
|
||||
```sh
|
||||
npx pear-multisig-link [quorom] [namespace] [...publicKeys]
|
||||
```
|
||||
|
||||
Help
|
||||
|
||||
```sh
|
||||
pear-multisig-link [flags] [quorum] [namespace] <publicKeys...>
|
||||
|
||||
Print project multisig link determined by inputs
|
||||
|
||||
By default quorum, namespace and publicKeys values of the pear.json
|
||||
multisig field determine the multisig link
|
||||
|
||||
Example - 2/3 must sign to approve
|
||||
pear.json: {
|
||||
"multisig": {
|
||||
"publicKeys": ["<pubkey1>", "<pubkey2>", "<pubkey3>"],
|
||||
"namespace": "my-org/my-app",
|
||||
"quorum": 2
|
||||
}
|
||||
}
|
||||
|
||||
Either --config or positional arguments may be specified, but not both
|
||||
|
||||
Arguments:
|
||||
[quorum] Optional. Number of required signers
|
||||
[namespace] Optional. Multisig namespace
|
||||
<publicKeys...> Public keys of signers
|
||||
|
||||
Flags:
|
||||
--config [path=./pear.json] Project pear.json config file - exclusive to arguments
|
||||
--help|-h Show help
|
||||
```
|
||||
|
||||
## Programattic
|
||||
|
||||
```js
|
||||
const multisigLink = require('pear-multisig-link')
|
||||
```
|
||||
|
||||
```js
|
||||
import multisigLink from 'pear-multisig-link'
|
||||
```
|
||||
|
||||
```js
|
||||
const link = multisigLink({
|
||||
publicKeys: ['pubkey1', 'pubkey2', 'pubkey3'],
|
||||
namespace: 'my-org/my-repo',
|
||||
quorum: 2
|
||||
})
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,5 +1,7 @@
|
||||
# pear-run
|
||||
|
||||
> **Name collision**: This document covers the **`pear-run` npm package** (Node API). It is unrelated to the deprecated **`pear run`** *CLI subcommand* from the `pear` binary; see [`Pear`](../utilities/pear.md) and upstream Pear release notes.
|
||||
|
||||
Launch a Pear app as a child process and get an IPC pipe.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# pear-runtime-legacy-storage
|
||||
|
||||
**Package**: `pear-runtime-legacy-storage` · **Version**: v1.1.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Holepunch ecosystem component.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [pear-runtime-legacy-storage](https://github.com/holepunchto/pear-runtime-legacy-storage)
|
||||
- Local mirror: `holepunchto_repos/pear-runtime-legacy-storage`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# pear-runtime-legacy-storage
|
||||
|
||||
Read app storage from the Pear platform `hyperdb` (read-only).
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install pear-runtime-legacy-storage
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
const getAppStorage = require('pear-runtime-legacy-storage')
|
||||
const storage = await getAppStorage('pear://my-app-key')
|
||||
if (!storage) {
|
||||
console.log('Not found or failed to open DB')
|
||||
} else {
|
||||
console.log(storage)
|
||||
}
|
||||
```
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,133 @@
|
||||
# pear-runtime-updater
|
||||
|
||||
**Package**: `pear-runtime-updater` · **Version**: v3.0.4 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Listens for OTA Pear App updates.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [pear-runtime-updater](https://github.com/holepunchto/pear-runtime-updater)
|
||||
- Local mirror: `holepunchto_repos/pear-runtime-updater`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# pear-runtime-updater
|
||||
|
||||
> Listens for OTA Pear App updates
|
||||
|
||||
```sh
|
||||
npm install pear-runtime-updater
|
||||
```
|
||||
|
||||
Listens for P2P over-the-air (OTA) updates for [Pear](https://docs.pears.com) apps. Replicates from a pear upgrade link and emits when a new version is available.
|
||||
|
||||
## MVP - EXPERIMENTAL
|
||||
|
||||
This boilerplate is MVP and Experimental.
|
||||
|
||||
## Usage
|
||||
|
||||
Example in node.js:
|
||||
|
||||
```js
|
||||
const PearRuntimeUpdater = require('pear-runtime-updater')
|
||||
const path = require('path')
|
||||
const Corestore = require('corestore')
|
||||
const Hyperswarm = require('hyperswarm')
|
||||
const goodbye = require('graceful-goodbye')
|
||||
const { version, upgrade } = require('./package.json')
|
||||
|
||||
const store = new Corestore('./my-app/corestore')
|
||||
|
||||
function getApp() {
|
||||
return path.join(process.resourcesPath, '../..')
|
||||
}
|
||||
|
||||
const updater = new PearRuntimeUpdater({
|
||||
dir: path.join(app.getPath('userData')),
|
||||
upgrade,
|
||||
version,
|
||||
app: getApp(), // path to .app / .AppImage
|
||||
name: 'name.ext', // <name>.app, <name>.AppImage, <name>.msix
|
||||
store
|
||||
})
|
||||
|
||||
await updater.ready()
|
||||
|
||||
updater.on('updating', () => console.log('Update downloading…'))
|
||||
updater.on('updated', async () => {
|
||||
console.log('Update ready')
|
||||
await updater.applyUpdate()
|
||||
app.relaunch()
|
||||
app.exit(0)
|
||||
})
|
||||
|
||||
const keyPair = await store.createKeyPair('pear-runtime')
|
||||
const swarm = new Hyperswarm({ keyPair })
|
||||
swarm.on('connection', (connection) => store.replicate(connection))
|
||||
swarm.join(updater.drive.core.discoveryKey, {
|
||||
client: true,
|
||||
server: false
|
||||
})
|
||||
|
||||
// handle teardown
|
||||
goodbye(async () => {
|
||||
await swarm.destroy()
|
||||
await updater.close()
|
||||
await store.close()
|
||||
})
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Peer-to-peer over-the-air (P2P OTA) update listening
|
||||
- Appends update content via [Hyperdrive](https://github.com/holepunchto/hyperdrive)
|
||||
- Emits when an update is in progress, update diffs and when it’s ready
|
||||
- `applyUpdate()` to atomic swap the new build (bundled apps; macOS/Linux)
|
||||
|
||||
## API
|
||||
|
||||
#### `const updater = new PearRuntimeUpdater(opts)`
|
||||
|
||||
- `opts.dir` – (required) Directory to store data (e.g. app data dir).
|
||||
- `opts.upgrade` – (required) Pear upgrade link (e.g. from `package.json` `upgrade` field).
|
||||
- `opts.name` – (required) Application name with extension.
|
||||
- `opts.store` - (required) Pass a [Corestore](https://github.com/holepunchto/corestore) to be used for updates.
|
||||
- `opts.version` – (optional) Current app version; used to decide if an update should be stored.
|
||||
- `opts.app` – (optional) Path to the app bundle (for bundled apps; used with `applyUpdate()`).
|
||||
- `opts.bundled` – (optional) Whether the app is bundled. Defaults to `!!opts.app`.
|
||||
- `opts.updates` – (optional) Set to false to opt out of updates.
|
||||
|
||||
#### `updater.on('updating')`
|
||||
|
||||
Emitted when an update is in progress.
|
||||
|
||||
#### `updater.on('updating-delta', data)`
|
||||
|
||||
Emitted with progress data while mirroring the update.
|
||||
|
||||
#### `updater.on('updated')`
|
||||
|
||||
Emitted when the update is fully downloaded and ready. After this, `updater.next` is the path to the staged update.
|
||||
|
||||
#### `updater.next`
|
||||
|
||||
After `updated`, the path to the staged update (e.g. for use with `applyUpdate()` or custom install logic).
|
||||
|
||||
#### `await updater.applyUpdate()`
|
||||
|
||||
Apply the update by swapping the current app with the received build through atomic swap. Only valid after `updated`, when `opts.bundled` is true.
|
||||
|
||||
#### `await updater.close()`
|
||||
|
||||
Shut it down. You should do this when closing your app for best performance.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,122 @@
|
||||
# pear-runtime
|
||||
|
||||
**Package**: `pear-runtime` · **Version**: v1.1.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Embeddable Pear Runtime.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [pear-runtime](https://github.com/holepunchto/pear-runtime)
|
||||
- Local mirror: `holepunchto_repos/pear-runtime`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# pear-runtime
|
||||
|
||||
> Embeddable Runtime library for [Pear](https://docs.pears.com) with P2P OTA updates, Bare workers and storage APIs
|
||||
|
||||
```sh
|
||||
npm install pear-runtime
|
||||
```
|
||||
|
||||
This module integrates Pear into JavaScript-based Desktop applications.
|
||||
|
||||
See [pear-mobile](https://github.com/holepunchto/pear-mobile) for Pear's embeddable runtime module for Mobile Devices.
|
||||
|
||||
## MVP - EXPERIMENTAL
|
||||
|
||||
This library is MVP and Experimental.
|
||||
|
||||
## OS Support
|
||||
|
||||
- MacOS
|
||||
- Linux
|
||||
- Windows
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const path = require('path')
|
||||
const PearRuntime = require('pear-runtime')
|
||||
const { version, upgrade } = require('./package.json')
|
||||
|
||||
function getAppPath() {
|
||||
if (!app.isPackaged) return null
|
||||
if (isLinux && process.env.APPIMAGE) return process.env.APPIMAGE
|
||||
if (isWindows) return process.execPath
|
||||
return path.join(process.resourcesPath, '..', '..')
|
||||
}
|
||||
|
||||
const pear = new PearRuntime({
|
||||
dir: path.join(__dirname, 'runtime-data'),
|
||||
version,
|
||||
upgrade,
|
||||
app: getAppPath() // path to .app / .AppImage / .msix
|
||||
})
|
||||
pear.on('error', console.error) // log network errors etc.
|
||||
pear.updater.on('updating', () => console.log('Updating...'))
|
||||
pear.updater.on('updated', () => pear.updater.applyUpdate())
|
||||
|
||||
const worker = PearRuntime.run(require.resolve('./worker.js'))
|
||||
worker.on('data', (data) => console.log('worker:', data.toString()))
|
||||
|
||||
// be sure to await pear.close() during process teardown
|
||||
```
|
||||
|
||||
## Quick Starts
|
||||
|
||||
### Electron
|
||||
|
||||
```sh
|
||||
git clone https://github.com/holepunchto/hello-pear-electron
|
||||
```
|
||||
|
||||
For end-to-end instructions from building to deploying with [Pear](https://docs.pears.com) see [hello-pear-electron](https://github.com/holepunchto/hello-pear-electron/) `README.md`.
|
||||
|
||||
### WebView
|
||||
|
||||
> Coming Soon
|
||||
|
||||
## Features
|
||||
|
||||
- Peer-to-Peer Over-the-Air (P2P OTA) updates (via [pear-runtime-updater](https://www.github.com/holepunchto/pear-runtime-updater))
|
||||
- Run workers in [Bare Runtime](https://github.com/holepunchto/bare)
|
||||
- Application storage management
|
||||
|
||||
## API
|
||||
|
||||
#### `IPC <stream.Duplex> = PearRuntime.run(path, args = [], opts = {})`
|
||||
|
||||
alias: [pear.run](#ipc-streamduplex--pearrunpath-args---opts--)
|
||||
|
||||
Start a [bare](https://github.com/holepunchto/bare) worker.
|
||||
Returns a duplex stream, the `IPC` pipe.
|
||||
|
||||
In the worker, `Bare.IPC` is the other end of the pipe.
|
||||
|
||||
Worker stdio is available at `IPC.stdin`, `IPC.stdout` & `IPC.stderr`.
|
||||
|
||||
#### `const pear = new PearRuntime(opts)`
|
||||
|
||||
- `opts.dir` – (required) Directory to store data (e.g. app data dir).
|
||||
- `opts.upgrade` – (required) Pear upgrade link (e.g. from `package.json` `upgrade` field).
|
||||
- `opts.name` - (required) The package.json `productName` of the app.
|
||||
- **`store`** - (optional) pass a [Corestore](https://github.com/holepunchto/corestore) to be used for updates. If passed `swarm` must also be passed. The `store` should be replicated over the `swarm`.
|
||||
- **`swarm`** - (optional) pass a [Hyperswarm](https://github.com/holepunchto/hyperswarm) to be used for swarming updates. If passed `store` must also be passed. The `store` should be replicated over the `swarm`.
|
||||
- `opts.version` – (optional) Current app version; used to decide if an update should be stored.
|
||||
- `opts.app` – (optional) Path to the app bundle (for bundled apps; used with `applyUpdate()`).
|
||||
- `opts.bundled` – (optional) Whether the app is bundled. Defaults to `!!opts.app`.
|
||||
- `opts.updates` – (optional) Set to false to opt out of updates.
|
||||
- `opts.storage` – (optional) Set peer-to-peer application storage path.
|
||||
|
||||
#### `IPC <stream.Duplex> = pear.run(path, args = [], opts = {})`
|
||||
|
||||
alias: [PearRu
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -12,6 +12,10 @@ npm i pear-stage
|
||||
|
||||
`pear-stage` syncs a local directory into a Pear app drive and returns a status stream.
|
||||
|
||||
### Ignore defaults (Pear CLI **v2.4+**)
|
||||
|
||||
The Pear CLI no longer auto-ignores `.git`, `.github`, `.DS_Store`, or `node_modules/.package-lock.json` during staging. Configure explicit patterns under **`pear.stage.ignore`** in your Pear app manifest when you need those exclusions.
|
||||
|
||||
## API
|
||||
|
||||
### `stage(link, opts)`
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
# gip-remote
|
||||
|
||||
**Package**: `gip-remote` · **Version**: v1.2.4 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Git+Pear remote DB for handling git data.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [gip-remote](https://github.com/holepunchto/gip-remote)
|
||||
- Local mirror: `holepunchto_repos/gip-remote`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# gip-remote
|
||||
|
||||
Git-into-Pear remote database. Store and replicate p2p Git repositories [HyperDB](https://github.com/holepunchto/hyperdb).
|
||||
|
||||
Git objects are stored raw, and rebuilt to file when needed. Built for the [Git+Pear remote transport](https://github.com/holepunchto/git-remote-punch-transport).
|
||||
|
||||
```
|
||||
npm install gip-remote
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const Corestore = require('corestore')
|
||||
const Hyperswarm = require('hyperswarm')
|
||||
const { Remote } = require('gip-remote')
|
||||
|
||||
const store = new Corestore('./my-store')
|
||||
const swarm = new Hyperswarm()
|
||||
swarm.on('connection', (conn) => {
|
||||
store.replicate(conn)
|
||||
})
|
||||
|
||||
// new remote
|
||||
const remote = new Remote(store.namespace('my-repo'), 'my-repo')
|
||||
await remote.ready()
|
||||
|
||||
console.log(remote.key) // public key
|
||||
|
||||
// remote remote!
|
||||
const remote2 = new Remote(
|
||||
store.namespace('my-other-repo'),
|
||||
'git+pear://0.1.iain5rkqfenyjrcod53tb61cq3egpwbk6cnd15ca3pqm39g7wf1y/my-other-repo'
|
||||
)
|
||||
await remote2.ready()
|
||||
```
|
||||
|
||||
### Push
|
||||
|
||||
```js
|
||||
// objects is a Map of oid => { type, size, data }
|
||||
await remote.push('main', commitOid, objects)
|
||||
```
|
||||
|
||||
### Fetch
|
||||
|
||||
```js
|
||||
const refs = await remote.getAllRefs()
|
||||
const objects = await remote.getRefObjects(commitOid)
|
||||
```
|
||||
|
||||
### toDrive
|
||||
|
||||
Get a Hyperdrive-compatible interface for a branch. Works with [mirror-drive](https://github.com/holepunchto/mirror-drive/).
|
||||
|
||||
```js
|
||||
const drive = await remote.toDrive('main')
|
||||
|
||||
const content = await drive.get('/README.md')
|
||||
|
||||
for await (const path of drive.list('/')) {
|
||||
console.log(path)
|
||||
}
|
||||
|
||||
// Mirror to a local Hyperdrive
|
||||
const mirror = drive.mirror(localDrive)
|
||||
await mirror.done()
|
||||
```
|
||||
|
||||
### toDisk
|
||||
|
||||
Write git objects directly to a `.git` directory on disk.
|
||||
|
||||
```js
|
||||
const { toDisk } = require('gip-remote/lib/git')
|
||||
|
||||
const objects = await remote.getRefObjects(commitOid)
|
||||
|
||||
await toDisk({
|
||||
gitDir: '/path/to/repo/.git',
|
||||
objects,
|
||||
refs: { 'refs/heads/main': commitOid },
|
||||
head: 'main'
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const remote = new Remote(opts)`
|
||||
|
||||
Create a new remote.
|
||||
|
||||
- `opts.name` - repository name
|
||||
- `opts.store` - a Corestore instance
|
||||
- `opts.swarm` - a Hyperswarm instance
|
||||
- `opts.key` - optional public key to open an existing remote
|
||||
- `opts.timeout` - peer discovery timeout in ms (default `240000`)
|
||||
|
||||
#### `remote.key`
|
||||
|
||||
Public key of the underlying Hypercore.
|
||||
|
||||
#### `remote.discoveryKey`
|
||||
|
||||
Discovery key used for swarming.
|
||||
|
||||
#### `await remote.push(branch, commitOid, objects)`
|
||||
|
||||
Push a commit. `objects` is a `Map<oid, { type, size, data }>`.
|
||||
|
||||
#### `await remote.getAllRefs()`
|
||||
|
||||
Returns an array of `{ ref, oid }`.
|
||||
|
||||
#### `await remote.getBranchRef(branch)`
|
||||
|
||||
Returns `{ ref, oid }` or `null`.
|
||||
|
||||
#### `await remote.getRefObjects(commitOid)`
|
||||
|
||||
Returns all stored objects for a commit.
|
||||
|
||||
#### `await remote.getObject(oid)`
|
||||
|
||||
Get a single object by OID.
|
||||
|
||||
#### `const drive = await remote.toDrive(branch)`
|
||||
|
||||
Returns a `RemoteDrive` or `null` if the branch doesn't exist. The drive is compatible with `mirror-drive`.
|
||||
|
||||
#### `await toDisk(opts)`
|
||||
|
||||
Write git objects to a `.git` directory.
|
||||
|
||||
- `opts.gitDir` - path to the `.git` directory (required)
|
||||
- `opts.objects` - array of `{ type, id, size, data }` (required)
|
||||
- `opts.refs` - object mapping ref names to OIDs, e.g. `{ 'refs/heads/main': commitOid }`
|
||||
- `opts.head` - branch name to set HEAD to, e.g. `'main'`
|
||||
- `opts.objectFormat` - hash algorithm, only `'sha1'` supported (default)
|
||||
- `opts.verifySizes` - verify declared sizes match buffer lengths (default `true`)
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,140 @@
|
||||
# gip-transport
|
||||
|
||||
**Package**: `gip-transport` · **Version**: v1.5.2 · **License**: ISC
|
||||
|
||||
## Summary
|
||||
|
||||
Git remote helper for P2P remotes — no server, just peers..
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [gip-transport](https://github.com/holepunchto/gip-transport)
|
||||
- Local mirror: `holepunchto_repos/gip-transport`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# Gip Transport
|
||||
|
||||
Git remote helper for P2P remotes — no server, just peers.
|
||||
|
||||
Uses [gip-remote](https://github.com/holepunchto/gip-remote) for the underlying Git-in-Pear database.
|
||||
|
||||
## Installation
|
||||
|
||||
Install the git remote helper globally:
|
||||
|
||||
```bash
|
||||
npm i -g gip-transport
|
||||
```
|
||||
|
||||
This installs `git-remote-git+pear` which git will automatically use when accessing `git+pear://` remotes, and the `gip` CLI for managing repositories and configuration.
|
||||
|
||||
## Usage
|
||||
|
||||
### Creating a Repository
|
||||
|
||||
```bash
|
||||
gip new my-repo
|
||||
```
|
||||
|
||||
### Adding a Remote
|
||||
|
||||
```bash
|
||||
git remote add origin git+pear://<key>/my-repo
|
||||
```
|
||||
|
||||
### Push & Fetch
|
||||
|
||||
Works like any git remote:
|
||||
|
||||
```bash
|
||||
git push origin main
|
||||
git fetch origin
|
||||
git clone git+pear://<key>/my-repo
|
||||
git push origin --delete my-branch
|
||||
```
|
||||
|
||||
### Seeding
|
||||
|
||||
Keep your repositories available to peers:
|
||||
|
||||
```bash
|
||||
gip seed
|
||||
```
|
||||
|
||||
Prints your public key and lists the repositories being seeded. Logs peer connections and block transfers as they happen:
|
||||
|
||||
```
|
||||
Seeding — Public key: 38ue8c5euscbjm8cqhan7psmgx9jpji5iey9aqjzf84749ghoqpo
|
||||
|
||||
my-repo — 42 blocks
|
||||
|
||||
+ Peer connected 7xk9m3f2
|
||||
↑ my-repo block 0 → 7xk9m3f2
|
||||
↑ my-repo block 1 → 7xk9m3f2
|
||||
```
|
||||
|
||||
### Your Public Key
|
||||
|
||||
Print your public key to share with blind peer operators:
|
||||
|
||||
```bash
|
||||
gip id
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration is stored in the local HyperDB database.
|
||||
|
||||
### Blind Peers
|
||||
|
||||
Blind peers relay your data for discoverability without seeing its contents. Add a blind peer mirror:
|
||||
|
||||
```bash
|
||||
gip config add blind-peers <z32-key>
|
||||
```
|
||||
|
||||
Remove one:
|
||||
|
||||
```bash
|
||||
gip config remove blind-peers <z32-key>
|
||||
```
|
||||
|
||||
View current config:
|
||||
|
||||
```bash
|
||||
gip config
|
||||
gip config get blind-peers
|
||||
```
|
||||
|
||||
### Progress Output
|
||||
|
||||
The transport provides git-like progress output during push and fetch operations:
|
||||
|
||||
- **Enumerating objects**: Counts objects being prepared for transfer
|
||||
- **Writing objects**: Shows percentage complete, object count, data size, and transfer rate
|
||||
- **Receiving objects**: Similar progress for fetch/clone operations
|
||||
|
||||
Progress is written to stderr to avoid interfering with git protocol communication on stdout.
|
||||
|
||||
## Development
|
||||
|
||||
Link the remote helper so git can find it:
|
||||
|
||||
```bash
|
||||
sudo ln -s $(pwd)/remote.js /usr/local/bin/git-remote-git+pear
|
||||
```
|
||||
|
||||
Git automatically looks for `git-remote-<protocol>` when accessing a remote.
|
||||
|
||||
## ToDo
|
||||
|
||||
- [ ] Multi-signer
|
||||
- [x] Deduplication — objects are not pushed if they already exist on the remote
|
||||
- [x] In-memory git packing via rebuild-git
|
||||
- [x] Blind peer support
|
||||
- [x] Branch deletion
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,30 @@
|
||||
# hrpc-swift
|
||||
|
||||
**Package**: `hrpc-swift` · **Version**: v0.1.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Swift code generator for HRPC.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [hrpc-swift](https://github.com/holepunchto/hrpc-swift)
|
||||
- Local mirror: `holepunchto_repos/hrpc-swift`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# hrpc-swift
|
||||
|
||||
Swift code generation for [HRPC](https://github.com/holepunchto/hrpc).
|
||||
|
||||
```
|
||||
npm i hrpc-swift
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,20 @@
|
||||
# oidc-publishing-sandbox
|
||||
|
||||
**Package**: `oidc-publishing-sandbox` · **Version**: v1.0.7 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Sandbox for testing OIDC publishing.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [oidc-publishing-sandbox](https://github.com/holepunchto/oidc-publishing-sandbox)
|
||||
- Local mirror: `holepunchto_repos/oidc-publishing-sandbox`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
_No README.md in clone; see upstream repository._
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,56 @@
|
||||
# oidc-publishing
|
||||
|
||||
**Package**: `oidc-publishing` · **Version**: v0.1.2 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
OIDC publishing tools for GitHub and npm.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [oidc-publishing](https://github.com/holepunchto/oidc-publishing)
|
||||
- Local mirror: `holepunchto_repos/oidc-publishing`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# oidc-publishing
|
||||
|
||||
OIDC publishing tools for GitHub and npm.
|
||||
|
||||
```
|
||||
npm i [-g] oidc-publishing
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `await setup([base][, options])`
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
options = {
|
||||
environment: 'npm',
|
||||
workflow: 'publish.yml',
|
||||
reviewers: []
|
||||
}
|
||||
```
|
||||
|
||||
## CLI
|
||||
|
||||
#### `oidc-publishing setup [flags] [entry]`
|
||||
|
||||
Flags include:
|
||||
|
||||
```
|
||||
--environment <name> The deployment environment name (default: npm)
|
||||
--workflow <file> The workflow file name (default: publish.yml)
|
||||
--reviewer <specifier> The team: or user: that should act as reviewer
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,4 +1,6 @@
|
||||
# protomux - Protocol Multiplexer
|
||||
# protomux v3.10.1 - Protocol Multiplexer
|
||||
|
||||
**Current npm version**: 3.10.1.
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
# react-native-notifier
|
||||
|
||||
**Package**: `@holepunchto/react-native-notifier` · **Version**: v2.0.3 · **License**: MIT
|
||||
|
||||
## Summary
|
||||
|
||||
Fast and simple in-app notifications for React Native.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [react-native-notifier](https://github.com/holepunchto/react-native-notifier)
|
||||
- Local mirror: `holepunchto_repos/react-native-notifier`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# react-native-notifier
|
||||
|
||||
[](https://www.npmjs.com/package/react-native-notifier)
|
||||
[](https://bundlephobia.com/result?p=react-native-notifier)
|
||||

|
||||
[](https://github.com/seniv/react-native-notifier/blob/master/LICENSE)
|
||||
|
||||
Fast, simple, and customizable in-app notifications for React Native
|
||||
|
||||

|
||||
|
||||
## Requirements
|
||||
|
||||
This library uses [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler), a perfect library for swipes, and other gesture events.
|
||||
|
||||
Please check their installation guide to install it properly: https://docs.swmansion.com/react-native-gesture-handler/docs/installation
|
||||
|
||||
## Installation
|
||||
```sh
|
||||
yarn add react-native-notifier
|
||||
```
|
||||
Or
|
||||
```sh
|
||||
npm install --save react-native-notifier
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Wrap your app with `NotifierWrapper`
|
||||
```js
|
||||
import { NotifierWrapper } from 'react-native-notifier';
|
||||
|
||||
const App = () => (
|
||||
<NotifierWrapper>
|
||||
<Navigation />
|
||||
</NotifierWrapper>
|
||||
);
|
||||
```
|
||||
Then call `Notifier.showNotification()` anywhere in code
|
||||
```js
|
||||
import { Notifier, Easing } from 'react-native-notifier';
|
||||
|
||||
Notifier.showNotification({
|
||||
title: 'John Doe',
|
||||
description: 'Hello! Can you help me with notifications?',
|
||||
duration: 0,
|
||||
showAnimationDuration: 800,
|
||||
showEasing: Easing.bounce,
|
||||
onHidden: () => console.log('Hidden'),
|
||||
onPress: () => console.log('Press'),
|
||||
hideOnPress: false,
|
||||
});
|
||||
```
|
||||
---
|
||||
|
||||
Or add `NotifierRoot` at end of your App.js component. With this approach you can show notification using reference to the `NotifierRoot`.
|
||||
|
||||
Note that `NotifierRoot` should be the last component to display notifications correctly. `Notifier.showNotification` is also available.
|
||||
```js
|
||||
import { NotifierRoot } from 'react-native-notifier';
|
||||
|
||||
function App() {
|
||||
const notifierRef = useRef();
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
title="Show Notification"
|
||||
onPress={() => notifierRef.current?.showNotification({ title: 'Using refs' })}
|
||||
/>
|
||||
<NotifierRoot ref={notifierRef} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
Both `NotifierWrapper` and `NotifierRoot` receive the same props.
|
||||
|
||||
Name | Type | Default | Description
|
||||
----------------------|------------------|-------------------------------|-------------
|
||||
omitGlobalMethodsHookup| Boolean | false | If set to `true`, global `Notifier` methods will not control this component. It's useful in case you have more than one `NotifierWrapper` or `NotifierRoot` rendered. If enabled, the only way to display notifications is using refs.
|
||||
useRNScreensOverlay | Boolean | false | use `FullWindowOverlay` component from `react-native-screens` library. If `true`, Notifier will be rendered above NativeStackNavigation modals and RN Modal on iOS. This Option will work only if `react-native-screens` library is installed. iOS Only.
|
||||
rnScreensOverlayViewStyle| ViewStyle | null | Style that will be used for RN View that is inside of FullWindowOverlay. iOS Only.
|
||||
|
||||
All parameters of the [`showNotification`](#showNotification) function can
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## Recent changelog (excerpt)
|
||||
|
||||
# Changelog
|
||||
|
||||
## v3.0.0-rc
|
||||
|
||||
### Breaking Changes
|
||||
- The library now internally uses `react-native-safe-area-context`. Make sure you have `react-native-safe-area-context` installed, and that `NotifierRoot/Wrapper` is wrapped by `SafeAreaProvider`.
|
||||
- `Component` is unmounted while the notification is not visible.
|
||||
- `containerStyle` now only accepts a simple style object and cannot be used to change animation. Use `animationFunction` instead.
|
||||
- The "Hide Timer" (`duration` param) now starts after the “appearing” animation finishes, rather than when it starts. If you use a long “appearing” animation, you may want to reduce the `duration` (3 seconds by default).
|
||||
- The `swipeEnabled` parameter has been removed. To disable swipes, set `swipeDirection: 'none'`.
|
||||
- The parameters `animationDuration`, `showAnimationDuration`, `hideAnimationDuration`, `swipeAnimationDuration`, `easing`, `showEasing`, `hideEasing`, `swipeEasing` have been removed. Use `showAnimationConfig`, `hideAnimationConfig`, `swipeOutAnimationConfig`, `resetSwipeAnimationConfig` instead.
|
||||
- The default `showAnimationConfig` is now set to a spring animation when `Component != NotifierComponents.Alert`.
|
||||
|
||||
### Features
|
||||
- Support for different positions. A notification can be placed at `top`, `bottom`, or any edge of the screen using the `position` parameter.
|
||||
- Introduced new params: `enterFrom`, `exitTo`, and `swipeDirection`. These control the direction of entering/exiting animations and allow swiping not only to the top but also left, right, and down.
|
||||
- New `animationFunction` parameter for creating custom animations.
|
||||
- Each notification now has its own ID. The default ID depends on the `idStrategy` parameter, and you can also assign one manually. If a notification with the same ID is already shown, the result of `showNotification` depends on `duplicateBehavior`.
|
||||
- New `duplicateBehavior` parameter describing how the Notifier should behave if a notification with the same ID is already shown.
|
||||
- New `idStrategy` parameter, which defines how a default ID is generated if none is provided.
|
||||
- New `updateNotification` method that updates a _currently visible_ notification.
|
||||
- New `shakeNotification` method that shakes a _currently visible_ notification to attract the user's attention and optionally resets the `duration` timer.
|
||||
- New `isNotificationVisible` method: Returns a boolean indicating if any notification is currently visible.
|
||||
- New methods: `updateById`, `shakeById`, `isVisibleById`, and `hideById`. Th
|
||||
|
||||
…(truncated)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,40 @@
|
||||
# corestore-snapshot
|
||||
|
||||
**Package**: `corestore-snapshot` · **Version**: v1.3.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Make a corestore snapshot for ci.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [corestore-snapshot](https://github.com/holepunchto/corestore-snapshot)
|
||||
- Local mirror: `holepunchto_repos/corestore-snapshot`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# corestore-snapshot
|
||||
|
||||
Little thing that snapshots corestore state to disk for stateless reuse
|
||||
|
||||
```
|
||||
npm install corestore-snapshot
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
# on ci
|
||||
corestore-snapshot --open --corestore=./store
|
||||
# ... mutate it
|
||||
corestore-snapshot --close --corestore=./store
|
||||
# commit the snapshot file
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,4 +1,6 @@
|
||||
# Corestore - Multi-Core Namespace Manager
|
||||
# Corestore v7.9.2 - Multi-Core Namespace Manager
|
||||
|
||||
**Current npm version**: 7.9.2.
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
# distributed-drive
|
||||
|
||||
**Package**: `distributed-drive` · **Version**: v0.1.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Drive-compatible unified view across multiple peers and drives over RPC.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [distributed-drive](https://github.com/holepunchto/distributed-drive)
|
||||
- Local mirror: `holepunchto_repos/distributed-drive`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# distributed-drive
|
||||
|
||||
A drive-compatible unified view across multiple peers and drives over RPC. Connect your devices, register drives, and browse everything as one folder.
|
||||
|
||||
> **Note:** This module was AI-generated with Claude and may need adjustments. Review before use in production.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const Hyperswarm = require('hyperswarm')
|
||||
const Localdrive = require('localdrive')
|
||||
const DistributedDrive = require('distributed-drive')
|
||||
|
||||
const drive = new DistributedDrive(new Localdrive('./movies'), new Localdrive('./music'))
|
||||
|
||||
const swarm = new Hyperswarm()
|
||||
swarm.join(topic)
|
||||
|
||||
swarm.on('connection', (stream) => drive.addPeer(stream))
|
||||
|
||||
// unified view — local + remote files merged
|
||||
for await (const entry of drive.list('/')) {
|
||||
console.log(entry.key)
|
||||
}
|
||||
|
||||
const buf = await drive.get('/photos/beach.jpg')
|
||||
```
|
||||
|
||||
## Try it
|
||||
|
||||
On machine A:
|
||||
|
||||
```
|
||||
node run.js
|
||||
```
|
||||
|
||||
On machine B (using the key printed by A):
|
||||
|
||||
```
|
||||
node run.js <key>
|
||||
```
|
||||
|
||||
Share a specific directory:
|
||||
|
||||
```
|
||||
node run.js -p ~/movies
|
||||
node run.js <key> -p ~/photos
|
||||
```
|
||||
|
||||
### REPL commands
|
||||
|
||||
```
|
||||
ls [path] list files
|
||||
cat <path> print file contents
|
||||
cp <path> [dest] copy remote file locally
|
||||
find <query> search filenames
|
||||
peers show connected peers
|
||||
exit quit
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
`new DistributedDrive(...drives, [opts])` — create a drive, optionally registering drives upfront.
|
||||
|
||||
`drive.register(drive)` / `drive.unregister(drive)` — add or remove a local drive.
|
||||
|
||||
`drive.addPeer(stream)` — add an encrypted stream from Hyperswarm. Opens a protomux-rpc channel. Peer is removed automatically on stream close.
|
||||
|
||||
`await drive.entry(path)` — get entry metadata. Checks local drives, then cache, then fans out to peers.
|
||||
|
||||
`await drive.get(path)` — get file contents as a buffer. Same lookup order.
|
||||
|
||||
`drive.list(prefix)` — readable stream of entries merged from all drives and peers, deduplicated by key.
|
||||
|
||||
`drive.createReadStream(path)` — readable stream of file contents.
|
||||
|
||||
## How it works
|
||||
|
||||
Each peer connection is symmetric — both sides share their registered drives and can query the other's. There is no client/server distinction. Metadata is cached lazily with [record-cache](https://github.com/mafintosh/record-cache) and disconnected peers are filtered on read. The RPC protocol uses [hyperschema](https://github.com/holepunchto/hyperschema) for encoding and [protomux-rpc](https://github.com/holepunchto/protomux-rpc) for transport.
|
||||
|
||||
Security is handled below this module — Hyperswarm connections are encrypted via secret-stream. The swarm topic acts as the shared secret.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,94 +0,0 @@
|
||||
# rocksdb-native
|
||||
|
||||
RocksDB bindings for JavaScript (via librocksdb).
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm i rocksdb-native
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`rocksdb-native` provides a JavaScript API for RocksDB, backed by `librocksdb`. It supports read/write batches and is used for local-only storage.
|
||||
|
||||
## API
|
||||
|
||||
### `new RocksDB(path)`
|
||||
|
||||
### Write batch
|
||||
|
||||
- `const w = db.write()`
|
||||
- `w.put(key, value)`
|
||||
- `w.del(key)`
|
||||
- `await w.flush()`
|
||||
|
||||
### Read batch
|
||||
|
||||
- `const r = db.read()`
|
||||
- `const p = r.get(key)`
|
||||
- `r.flush()`
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic write/read
|
||||
|
||||
```js
|
||||
const RocksDB = require('rocksdb-native')
|
||||
|
||||
const db = new RocksDB('./example.db')
|
||||
const w = db.write()
|
||||
w.put('hello', 'world')
|
||||
await w.flush()
|
||||
|
||||
const r = db.read()
|
||||
const p = r.get('hello')
|
||||
r.flush()
|
||||
console.log(await p)
|
||||
```
|
||||
|
||||
### Batch deletes
|
||||
|
||||
```js
|
||||
const w = db.write()
|
||||
w.del('old-key')
|
||||
await w.flush()
|
||||
```
|
||||
|
||||
### Multiple reads
|
||||
|
||||
```js
|
||||
const r = db.read()
|
||||
const a = r.get('a')
|
||||
const b = r.get('b')
|
||||
r.flush()
|
||||
console.log(await a, await b)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use batches to reduce write amplification.
|
||||
|
||||
## Performance
|
||||
|
||||
- LSM-tree storage performs well on SSDs and large datasets.
|
||||
|
||||
## Security
|
||||
|
||||
- Store databases in protected directories.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Handle errors on `flush()` for I/O failures.
|
||||
|
||||
## Integration
|
||||
|
||||
- Used by local Hypercore storage and indexing tools.
|
||||
|
||||
## Notes
|
||||
|
||||
- On Linux, `libatomic` must be installed.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
@@ -0,0 +1,98 @@
|
||||
# brittle-snapshot
|
||||
|
||||
**Package**: `brittle-snapshot` · **Version**: v1.0.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Traditional snapshots for brittle.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [brittle-snapshot](https://github.com/holepunchto/brittle-snapshot)
|
||||
- Local mirror: `holepunchto_repos/brittle-snapshot`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# brittle-snapshot
|
||||
|
||||
Snapshot testing for [brittle](https://github.com/holepunchto/brittle). One snapshot file per test file, multiple snapshots per file.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm i brittle-snapshot
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const test = require('brittle')
|
||||
const { matchSnapshot } = require('brittle-snapshot')
|
||||
|
||||
test('render heading', (t) => {
|
||||
const html = render('<h1>hello</h1>')
|
||||
|
||||
matchSnapshot(t, html)
|
||||
matchSnapshot(t, render('<h1>world</h1>'), 'second heading')
|
||||
})
|
||||
```
|
||||
|
||||
Snapshots are written to a `__snapshots__` directory alongside the calling test file, named after it:
|
||||
|
||||
```
|
||||
test/
|
||||
render.js
|
||||
__snapshots__/
|
||||
render.snap
|
||||
```
|
||||
|
||||
Each `.snap` file contains all snapshots for that test file:
|
||||
|
||||
```
|
||||
=== render heading > 1 ===
|
||||
<h1>hello</h1>
|
||||
=== render heading > second heading ===
|
||||
<h1>world</h1>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `matchSnapshot(t, source, [desc])`
|
||||
|
||||
Compare `source` against a stored snapshot using character-level diffing.
|
||||
|
||||
#### `matchSnapshotCSS(t, source, [desc])`
|
||||
|
||||
Compare using CSS-aware diffing.
|
||||
|
||||
#### `matchSnapshotJSON(t, source, [desc])`
|
||||
|
||||
Compare using JSON-aware diffing.
|
||||
|
||||
All functions take:
|
||||
|
||||
- `t` — a brittle test instance
|
||||
- `source` — string to snapshot
|
||||
- `desc` — optional label for the snapshot key (defaults to an auto-incrementing counter)
|
||||
|
||||
## Updating snapshots
|
||||
|
||||
Run with `--update` or `-u` to overwrite existing snapshots:
|
||||
|
||||
```
|
||||
bare test/render.js --update
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
npm test -- --update
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,70 @@
|
||||
# check-npm-maintainers
|
||||
|
||||
**Package**: `check-npm-maintainers` · **Version**: v1.0.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Check transitive maintainers.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [check-npm-maintainers](https://github.com/holepunchto/check-npm-maintainers)
|
||||
- Local mirror: `holepunchto_repos/check-npm-maintainers`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# check-npm-maintainers
|
||||
|
||||
Check transitive npm maintainers of all dependencies in a project.
|
||||
|
||||
Reports packages where:
|
||||
|
||||
- A key owner is missing from the maintainers
|
||||
- Maintainers include people not in the trusted owners list
|
||||
- All maintainers are external (no trusted or key owners)
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm i -g check-npm-maintainers@latest
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Create a trusted owners file (one username per line):
|
||||
|
||||
```
|
||||
npm-username-1
|
||||
npm-username-2
|
||||
```
|
||||
|
||||
Then run from a project directory with a `package.json`:
|
||||
|
||||
```sh
|
||||
check-npm-maintainers owners.txt
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```
|
||||
--prod Only check production dependencies
|
||||
--key-owner <username> Key owners to verify (can be repeated)
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Check only production dependencies:
|
||||
|
||||
```sh
|
||||
check-npm-maintainers --prod owners.txt
|
||||
```
|
||||
|
||||
Check with multiple key owners:
|
||||
|
||||
```sh
|
||||
check-npm-maintainers --key-owner npm-username-1 --key-owner npm-username-2 owners.txt
|
||||
```
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,34 @@
|
||||
# cmake-android
|
||||
|
||||
**Package**: `cmake-android` · **Version**: v0.1.4 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Android utilities for CMake.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [cmake-android](https://github.com/holepunchto/cmake-android)
|
||||
- Local mirror: `holepunchto_repos/cmake-android`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# cmake-android
|
||||
|
||||
Android utilities for CMake.
|
||||
|
||||
```
|
||||
npm i cmake-android
|
||||
```
|
||||
|
||||
```cmake
|
||||
find_package(cmake-android REQUIRED PATHS node_modules/cmake-android)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,34 @@
|
||||
# cmake-java
|
||||
|
||||
**Package**: `cmake-java` · **Version**: v0.1.2 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Java utilities for CMake.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [cmake-java](https://github.com/holepunchto/cmake-java)
|
||||
- Local mirror: `holepunchto_repos/cmake-java`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# cmake-java
|
||||
|
||||
Java utilities for CMake.
|
||||
|
||||
```
|
||||
npm i cmake-java
|
||||
```
|
||||
|
||||
```cmake
|
||||
find_package(cmake-java REQUIRED PATHS node_modules/cmake-java)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,136 @@
|
||||
# electron-devtools-mcp
|
||||
|
||||
**Package**: `chrome-devtools-mcp` · **Version**: v0.20.3 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
MCP server for Chrome DevTools.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [electron-devtools-mcp](https://github.com/holepunchto/electron-devtools-mcp)
|
||||
- Local mirror: `holepunchto_repos/electron-devtools-mcp`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# Chrome DevTools MCP
|
||||
|
||||
[](https://npmjs.org/package/chrome-devtools-mcp)
|
||||
|
||||
`chrome-devtools-mcp` lets your coding agent (such as Gemini, Claude, Cursor or Copilot)
|
||||
control and inspect a live Chrome browser. It acts as a Model-Context-Protocol
|
||||
(MCP) server, giving your AI coding assistant access to the full power of
|
||||
Chrome DevTools for reliable automation, in-depth debugging, and performance analysis.
|
||||
|
||||
## [Tool reference](./docs/tool-reference.md) | [Changelog](./CHANGELOG.md) | [Contributing](./CONTRIBUTING.md) | [Troubleshooting](./docs/troubleshooting.md) | [Design Principles](./docs/design-principles.md)
|
||||
|
||||
## Key features
|
||||
|
||||
- **Get performance insights**: Uses [Chrome
|
||||
DevTools](https://github.com/ChromeDevTools/devtools-frontend) to record
|
||||
traces and extract actionable performance insights.
|
||||
- **Advanced browser debugging**: Analyze network requests, take screenshots and
|
||||
check browser console messages (with source-mapped stack traces).
|
||||
- **Reliable automation**. Uses
|
||||
[puppeteer](https://github.com/puppeteer/puppeteer) to automate actions in
|
||||
Chrome and automatically wait for action results.
|
||||
|
||||
## Disclaimers
|
||||
|
||||
`chrome-devtools-mcp` exposes content of the browser instance to the MCP clients
|
||||
allowing them to inspect, debug, and modify any data in the browser or DevTools.
|
||||
Avoid sharing sensitive or personal information that you don't want to share with
|
||||
MCP clients.
|
||||
|
||||
`chrome-devtools-mcp` officially supports Google Chrome and [Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing/) only.
|
||||
Other Chromium-based browser may work, but this is not guaranteed, and you may encounter unexpected behavior. Use at your own discretion.
|
||||
We are committed to providing fixes and support for the latest version of [Extended Stable Chrome](https://chromiumdash.appspot.com/schedule).
|
||||
|
||||
Performance tools may send trace URLs to the Google CrUX API to fetch real-user
|
||||
experience data. This helps provide a holistic performance picture by
|
||||
presenting field data alongside lab data. This data is collected by the [Chrome
|
||||
User Experience Report (CrUX)](https://developer.chrome.com/docs/crux). To disable
|
||||
this, run with the `--no-performance-crux` flag.
|
||||
|
||||
## **Usage statistics**
|
||||
|
||||
Google collects usage statistics (such as tool invocation success rates, latency, and environment information) to improve the reliability and performance of Chrome DevTools MCP.
|
||||
|
||||
Data collection is **enabled by default**. You can opt-out by passing the `--no-usage-statistics` flag when starting the server:
|
||||
|
||||
```json
|
||||
"args": ["-y", "chrome-devtools-mcp@latest", "--no-usage-statistics"]
|
||||
```
|
||||
|
||||
Google handles this data in accordance with the [Google Privacy Policy](https://policies.google.com/privacy).
|
||||
|
||||
Google's collection of usage statistics for Chrome DevTools MCP is independent from the Chrome browser's usage statistics. Opting out of Chrome metrics does not automatically opt you out of this tool, and vice-versa.
|
||||
|
||||
Collection is disabled if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.
|
||||
|
||||
## Requirements
|
||||
|
||||
- [Node.js](https://nodejs.org/) v20.19 or a newer [latest maintenance LTS](https://github.com/nodejs/Release#release-schedule) version.
|
||||
- [Chrome](https://www.google.com/chrome/) current stable version or newer.
|
||||
- [npm](https://www.npmjs.com/)
|
||||
|
||||
## Getting started
|
||||
|
||||
Add the following config to your MCP client:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"chrome-devtools": {
|
||||
"com
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## Recent changelog (excerpt)
|
||||
|
||||
# Changelog
|
||||
|
||||
## [0.20.3](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.20.2...chrome-devtools-mcp-v0.20.3) (2026-03-20)
|
||||
|
||||
|
||||
### 🛠️ Fixes
|
||||
|
||||
* mark categoryExtensions flag mutually exclusive with autoConnect ([#1202](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1202)) ([8c2a7fc](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/8c2a7fc21ead6091567e85608f7916c001ccc7db)), closes [#1072](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1072)
|
||||
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
* **memory:** release old navigation request in NetworkCollector ([#1200](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1200)) ([1e6456c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1e6456ce222a8f392341a530b2340336c7a1ab02))
|
||||
* use CDP to find open DevTools pages (reland) ([#1210](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1210)) ([53483bc](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/53483bc637566658754d781d88f4353ad47f44a7))
|
||||
|
||||
## [0.20.2](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.20.1...chrome-devtools-mcp-v0.20.2) (2026-03-18)
|
||||
|
||||
|
||||
### 📄 Documentation
|
||||
|
||||
* add troubleshooting for Claude Code plugin HTTPS clone failures ([#1195](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1195)) ([d082ca4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d082ca4ecd35a023d09f9c1ff949d5fb0c3fb069))
|
||||
|
||||
## [0.20.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.20.0...chrome-devtools-mcp-v0.20.1) (2026-03-16)
|
||||
|
||||
|
||||
### 🛠️ Fixes
|
||||
|
||||
* update VS Code manual installation powershell command ([#1151](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1151)) ([6c64a5b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6c64a5b543714796b25a12dc6f2be7a1e683e8bd))
|
||||
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
* use CDP to find open DevTools pages. ([#1150](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1150)) ([94de19c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/94de19cdcdae9e31d0962b273ce352dc248eb5a8))
|
||||
|
||||
## [0.20.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.19.0...chrome-devtools-mcp-v0.20.0) (2026-03-11)
|
||||
|
||||
|
||||
### 🎉 Features
|
||||
|
||||
* experimental `chrome-devtools` CLI ([#1100](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1100)) ([1ac574e](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1ac574e7154948e86e41
|
||||
|
||||
…(truncated)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,54 @@
|
||||
# electron-forge-maker-appimage
|
||||
|
||||
**Package**: `@holepunchto/electron-forge-maker-appimage` · **Version**: v1.0.1 · **License**: MIT
|
||||
|
||||
## Summary
|
||||
|
||||
An electron-forge builder for AppImage..
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [electron-forge-maker-appimage](https://github.com/holepunchto/electron-forge-maker-appimage)
|
||||
- Local mirror: `holepunchto_repos/electron-forge-maker-appimage`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# Electron Forge: AppImage
|
||||
|
||||
This is an [electron-forge](https://www.electronforge.io/) builder for [AppImage](https://appimage.org/).
|
||||
|
||||
This project is based on several existing projects:
|
||||
- [electron-forge-maker-appimage](https://www.npmjs.com/package/electron-forge-maker-appimage)
|
||||
- [saleae/electron-forge-maker-appimage](https://github.com/saleae/electron-forge-maker-appimage)
|
||||
- [@pengx17/electron-forge-maker-appimage](https://www.npmjs.com/package/@pengx17/electron-forge-maker-appimage)
|
||||
- [@forkprince/electron-forge-maker-appimage](https://www.npmjs.com/package/@forkprince/electron-forge-maker-appimage)
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
npm install @holepunchto/electron-forge-maker-appimage --save-dev
|
||||
```
|
||||
|
||||
## forge.config.js
|
||||
|
||||
```js
|
||||
makers: [
|
||||
{
|
||||
name: "@holepunchto/electron-forge-maker-appimage",
|
||||
platforms: ["linux"],
|
||||
config: {
|
||||
productName: "Re:Lunatic Player",
|
||||
icons: [
|
||||
{
|
||||
file: "./src/img/logo.png",
|
||||
size: 256
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,30 @@
|
||||
# electron-forge-maker-flatpak
|
||||
|
||||
**Package**: `@holepunchto/electron-forge-maker-flatpak` · **Version**: v0.0.2 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
repo-template.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [electron-forge-maker-flatpak](https://github.com/holepunchto/electron-forge-maker-flatpak)
|
||||
- Local mirror: `holepunchto_repos/electron-forge-maker-flatpak`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# repo-template
|
||||
|
||||
Template repository for creating packages
|
||||
|
||||
## Usage
|
||||
|
||||
tbd
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,30 @@
|
||||
# electron-forge-maker-snap
|
||||
|
||||
**Package**: `@holepunchto/electron-forge-maker-snap` · **Version**: v0.0.8 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
repo-template.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [electron-forge-maker-snap](https://github.com/holepunchto/electron-forge-maker-snap)
|
||||
- Local mirror: `holepunchto_repos/electron-forge-maker-snap`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# @holepunchto/electron-forge-maker-snap
|
||||
|
||||
Template repository for creating packages
|
||||
|
||||
## Usage
|
||||
|
||||
tbd
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,52 @@
|
||||
# msix-manager
|
||||
|
||||
**Package**: `msix-manager` · **Version**: v0.2.5 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Install and update MSIX packages from JavaScript.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [msix-manager](https://github.com/holepunchto/msix-manager)
|
||||
- Local mirror: `holepunchto_repos/msix-manager`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# msix-manager
|
||||
|
||||
Install and update MSIX packages from JavaScript.
|
||||
|
||||
```
|
||||
npm i msix-manager
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const MSIXManager = require('msix-manager')
|
||||
|
||||
const manager = new MSIXManager()
|
||||
|
||||
manager
|
||||
.addPackage('./App.msix')
|
||||
.on('progress', (progress) => {
|
||||
console.log('Progress', progress)
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
console.log('Finished')
|
||||
},
|
||||
(err) => {
|
||||
console.log('Failed', err)
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,20 @@
|
||||
# pear-ci-example
|
||||
|
||||
**Package**: `pear-ci-example` · **Version**: version n/a · **License**: see repository
|
||||
|
||||
## Summary
|
||||
|
||||
Holepunch ecosystem component.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [pear-ci-example](https://github.com/holepunchto/pear-ci-example)
|
||||
- Local mirror: `holepunchto_repos/pear-ci-example`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
See workflow. Just using a dummy seed in the demo
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,130 @@
|
||||
# pear-ci-multisig
|
||||
|
||||
**Package**: `pear-ci-multisig` · **Version**: v0.0.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Specialized subset of pear multisig CLI for CI pipelines.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [pear-ci-multisig](https://github.com/holepunchto/pear-ci-multisig)
|
||||
- Local mirror: `holepunchto_repos/pear-ci-multisig`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# pear-ci-multisig
|
||||
|
||||
> Specialized subset of `pear multisig` CLI for CI pipelines
|
||||
|
||||
## Commands
|
||||
|
||||
### `link`
|
||||
|
||||
Print the deterministic multisig pear link.
|
||||
|
||||
Reads config from `pear.json` by default, or from `--config`. You can also provide the multisig fields directly with flags.
|
||||
|
||||
```sh
|
||||
npx pear-ci-multisig link
|
||||
```
|
||||
|
||||
```sh
|
||||
npx pear-ci-multisig link --config path/to/pear.json
|
||||
```
|
||||
|
||||
```sh
|
||||
npx pear-ci-multisig link --quorum 2 --namespace my-org/my-app --pubkey <publicKey1> --pubkey <publicKey2>
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
- `--config <path>` — path to `pear.json`
|
||||
- `--quorum <n>` — number of required signers
|
||||
- `--namespace <ns>` — multisig namespace
|
||||
- `--pubkey <key>` — signer public key, repeatable
|
||||
|
||||
Notes:
|
||||
|
||||
- `--config` cannot be combined with `--quorum`, `--namespace`, or `--pubkey`
|
||||
- when no flags are provided, `link` reads `pear.json` directly and expects a top-level `multisig` field
|
||||
|
||||
### `pear.json`
|
||||
|
||||
Default configuration file used by all commands when `--config` not specified.
|
||||
|
||||
Location:
|
||||
|
||||
- defaults to `./pear.json`
|
||||
|
||||
Required structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"multisig": {
|
||||
"namespace": "my-org/my-app",
|
||||
"quorum": <int>,
|
||||
"publicKeys": [
|
||||
"<publicKey1>",
|
||||
"<publicKeyN...>"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Fields:
|
||||
|
||||
- `multisig` — required object
|
||||
- `multisig.namespace` — required string identifying the multisig namespace
|
||||
- `multisig.quorum` — required integer specifying the number of required signatures
|
||||
- `multisig.publicKeys` — required array of signer public keys
|
||||
- each entry must be a hypercore-id encoded public key
|
||||
- array must contain at least one key
|
||||
|
||||
Behavior:
|
||||
|
||||
- `link` reads `pear.json` directly when no flags are provided
|
||||
- `request` loads multisig configuration from this file unless flags are used
|
||||
- `--config <path>` overrides the default location
|
||||
- `--quorum`, `--namespace`, and `--pubkey` flags may be used instead of a file
|
||||
- `--config` cannot be combined with those flags
|
||||
|
||||
Validation errors occur if:
|
||||
|
||||
- `multisig` is missing
|
||||
- `namespace` is missing
|
||||
- `quorum` is missing
|
||||
- `publicKeys` is missing or empty
|
||||
|
||||
---
|
||||
|
||||
### `request`
|
||||
|
||||
Create a signing request from a versioned source link.
|
||||
|
||||
```sh
|
||||
npx pear-ci-multisig request --config path/to/pear.json <verlink>
|
||||
```
|
||||
|
||||
```sh
|
||||
npx pear-ci-multisig request --quorum 2 --namespace my-org/my-app --pubkey <publicKey1> --pubkey <publicKey2> <verlink>
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
- `--config <path>` — path to `pear.json`
|
||||
- `--quorum <n>` — number of required signers
|
||||
- `--namespace <ns>` — multisig namespace
|
||||
- `--pubkey <key>` — signer public key, repeatable
|
||||
- `--force` — skip requestability checks
|
||||
- `--peer-update-timeout <ms>` — timeout for peer updates
|
||||
|
||||
Arguments:
|
||||
|
||||
- `<verlink>` — versioned source pear link
|
||||
|
||||
---
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,96 @@
|
||||
# pear-ci
|
||||
|
||||
**Package**: `pear-ci` · **Version**: v0.0.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Stateless stage for applications distributed with pear-runtime.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [pear-ci](https://github.com/holepunchto/pear-ci)
|
||||
- Local mirror: `holepunchto_repos/pear-ci`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# pear-ci
|
||||
|
||||
A CI staging tool for [Hyperdrive](https://github.com/holepunchto/hyperdrive). Mirrors a local directory into a Hyperdrive, replicates it over [Hyperswarm](https://github.com/holepunchto/hyperswarm), and writes a snapshot of core lengths so subsequent runs only sync what changed.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install pear-ci
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const PearCI = require('pear-ci')
|
||||
|
||||
const primaryKey = Buffer.from('<32-byte-hex-key>', 'hex')
|
||||
|
||||
const ci = new PearCI(
|
||||
primaryKey, // deterministic key for the corestore
|
||||
'my-app', // drive namespace name
|
||||
'./snapshot.json', // path to read/write the snapshot
|
||||
'./dist', // local directory to stage
|
||||
'./storage', // corestore storage path
|
||||
false // dryRun
|
||||
)
|
||||
|
||||
ci.on('diff', (diff) => console.log('changed:', diff))
|
||||
ci.on('synced', () => console.log('all peers caught up'))
|
||||
|
||||
await ci.stage()
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `const ci = new PearCI(primaryKey, name, snapshot, target, storage, dryRun, [opts])`
|
||||
|
||||
Creates a new PearCI instance. Does not open any resources until `ready()` or `stage()` is called.
|
||||
|
||||
| Argument | Type | Description |
|
||||
| ---------------- | --------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `primaryKey` | `Buffer` | 32-byte key passed to `Corestore`. Determines the identity of the drive across runs. |
|
||||
| `name` | `string` | Namespace name used to derive the Hyperdrive from the store. |
|
||||
| `snapshot` | `string` | File path for the JSON snapshot. Read on open to pre-seed cores; written on close with updated lengths. |
|
||||
| `target` | `string` | Path to the local directory to mirror into the drive. |
|
||||
| `storage` | `string` | Path for Corestore storage. |
|
||||
| `dryRun` | `boolean` | When `true`, diffs are computed and emitted but nothing is written to the drive. |
|
||||
| `opts.bootstrap` | `array` | Optional Hyperswarm bootstrap nodes. Useful for testing with `@hyperswarm/testnet`. |
|
||||
|
||||
### `await ci.stage()`
|
||||
|
||||
Opens the instance (if not already open), mirrors `target` into the drive, waits for all connected peers to replicate the new blocks, emits `synced`, then closes.
|
||||
|
||||
Calling `stage()` is the primary entry point — you do not need to call `ready()` manually.
|
||||
|
||||
### `await ci.ready()`
|
||||
|
||||
Opens the corestore, swarm, and drive. Joins all known discovery keys. If a snapshot exists, blocks until all cores have downloaded to their recorded lengths before resolving.
|
||||
|
||||
### `await ci.close()`
|
||||
|
||||
Writes the snapshot, then tears down the swarm, local drive, Hyperdrive, and corestore.
|
||||
|
||||
### Events
|
||||
|
||||
#### `ci.on('diff', (diff) => {})`
|
||||
|
||||
Emitted for each file that differs between the local directory and the drive. `diff` is the object produced by [mirror-drive](https://github.com/holepunchto/mirror-drive).
|
||||
|
||||
#### `ci.on('synced', () => {})`
|
||||
|
||||
Emitted once after staging completes and all peers have acknowledged the new blocks, just before the instance closes.
|
||||
|
||||
## Snapshot file
|
||||
|
||||
The snapshot is a JSON array written to `snapshot` on every close. Each entry records a core's public key, its length at close time, and any namespace alias information. On the next open, PearCI reads this file an
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,30 @@
|
||||
# repo-template
|
||||
|
||||
**Package**: `@holepunchto/repo-template` · **Version**: v0.0.1 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
repo-template.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [repo-template](https://github.com/holepunchto/repo-template)
|
||||
- Local mirror: `holepunchto_repos/repo-template`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# repo-template
|
||||
|
||||
Template repository for creating packages
|
||||
|
||||
## Usage
|
||||
|
||||
tbd
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -0,0 +1,92 @@
|
||||
# slack-build-status
|
||||
|
||||
**Package**: `slack-build-status` · **Version**: v1.0.0 · **License**: see repository
|
||||
|
||||
## Summary
|
||||
|
||||
Holepunch ecosystem component.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [slack-build-status](https://github.com/holepunchto/slack-build-status)
|
||||
- Local mirror: `holepunchto_repos/slack-build-status`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# slack-build-status
|
||||
|
||||
GitHub Actions for posting and updating build status messages in Slack. Creates a rich message with grouped build statuses, changelogs, and emoji indicators — then updates individual builds as they complete.
|
||||
|
||||
## Actions
|
||||
|
||||
### `create`
|
||||
|
||||
Post an initial build status message.
|
||||
|
||||
| Input | Required | Example | Description |
|
||||
|---|---|---|---|
|
||||
| `token` | yes | `xoxb-1234567890-1234567890123-abc` | Slack Bot OAuth token |
|
||||
| `channel-id` | yes | `C0123456789` | Slack channel ID |
|
||||
| `builds` | yes | `[{"name":"apk","label":"APK","group":"Android","status":"running"}]` | JSON array of builds: `{name, label, group, status?, link?}` |
|
||||
| `version` | yes | `1.2.3` | Build version string |
|
||||
| `branch` | yes | `main` | Git branch name |
|
||||
| `git-url` | yes | `https://github.com/owner/repo/tree/main` | URL to the git commit/branch |
|
||||
| `changelog-from` | no | `v1.0.0` | Git ref to generate changelog from (auto-generates changelog and compare URL) |
|
||||
| `changelog` | no | `• 91a4e0548 - feat: add login (#1)` | Manual changelog text, overrides `changelog-from` (`#N` and `(#N)` are auto-linked) |
|
||||
| `changelog-compare-url` | no | `https://github.com/owner/repo/compare/v1.0.0...v1.1.0` | Manual compare URL, overrides auto-generated one |
|
||||
| `icon` | no | `:app-icon:` | Icon emoji to prepend to header |
|
||||
| `extra-badges` | no | `:badge-staging:` | Additional badge emojis for the header |
|
||||
| `thread-replies` | no | `[{"text":"Version check: OK"}]` | JSON array of thread replies |
|
||||
| `notify-users` | no | `<@U0123> <@U0456>` | Slack user mentions to CC in thread |
|
||||
| `repo` | no | `owner/repo` | GitHub repo for PR link detection (defaults to current) |
|
||||
|
||||
| Output | Description |
|
||||
|---|---|
|
||||
| `ts` | Slack message timestamp (pass to `update`/`cancel-all`/`upload`) |
|
||||
|
||||
### `update`
|
||||
|
||||
Update a specific build's status in an existing message.
|
||||
|
||||
| Input | Required | Example | Description |
|
||||
|---|---|---|---|
|
||||
| `token` | yes | `xoxb-1234567890-1234567890123-abc` | Slack Bot OAuth token |
|
||||
| `channel-id` | yes | `C0123456789` | Slack channel ID |
|
||||
| `ts` | yes | `1234567890.123456` | Message timestamp from `create` |
|
||||
| `build-name` | yes | `apk` | Build name to update (must match `name` from `create`) |
|
||||
| `status` | yes | `success` | New status: `success`, `failure`, `cancelled`, `skipped`, or GitHub `job.status` |
|
||||
| `link` | no | `https://example.com/download/app.apk` | URL to attach (e.g. artifact download link) |
|
||||
| `file-path` | no | `build/outputs/app.apk` | File to upload to thread and link to this build |
|
||||
| `also-update` | no | `[{"name":"aab","status":"running"}]` | JSON array of additional updates: `{name, status, link?}` |
|
||||
|
||||
### `cancel-all`
|
||||
|
||||
Mark all pending/running builds as cancelled.
|
||||
|
||||
| Input | Required | Example | Description |
|
||||
|---|---|---|---|
|
||||
| `token` | yes | `xoxb-1234567890-1234567890123-abc` | Slack Bot OAuth token |
|
||||
| `channel-id` | yes | `C0123456789` | Slack channel ID |
|
||||
| `ts` | yes | `1234567890.123456` | Message timestamp from `create` |
|
||||
|
||||
### `upload`
|
||||
|
||||
Upload a file to the message thread.
|
||||
|
||||
| Input | Required | Example | Description |
|
||||
|---|---|---|---|
|
||||
| `token` | yes | `xoxb-1234567890-1234567890123-abc` | Slack Bot OAuth token |
|
||||
| `channel-id` | yes | `C0123456789` | Slack channel ID |
|
||||
| `ts` | yes | `1234567890.123456` | Message thread timestamp |
|
||||
| `file-path` | yes | `build/outputs/app.apk` | Path to the file to upload |
|
||||
| `filename` | no | `app-v1.2.3.apk` | Override filename (defaults to basename) |
|
||||
|
||||
| Output | Description |
|
||||
|---|---|
|
||||
|
|
||||
|
||||
…(truncated; see full README in repo)…
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,4 +1,6 @@
|
||||
# Autobase - Multiwriter Data Structure
|
||||
# Autobase v7.27.3 - Multiwriter Data Structure
|
||||
|
||||
**Current npm version**: 7.27.3 ([holepunchto/autobase](https://github.com/holepunchto/autobase)). Recent patch releases refine recovery paths and internal assertions; follow upstream `CHANGELOG.md` when upgrading.
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# blind-peer-router
|
||||
|
||||
**Package**: `blind-peer-router` · **Version**: v0.2.2 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Single-writer RPC service mapping content keys to blind peer assignments.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [blind-peer-router](https://github.com/holepunchto/blind-peer-router)
|
||||
- Local mirror: `holepunchto_repos/blind-peer-router`
|
||||
|
||||
## README (from clone)
|
||||
|
||||

|
||||
|
||||
# blind-peer-router
|
||||
|
||||
> **POC** — This is a proof-of-concept still. Breaking changes possible till the V1 release.
|
||||
|
||||
Single-writer RPC service that maps content keys to blind peer assignments. Clients request peers for a given content key and the service resolves the closest configured blind peers by XOR distance, persisting assignments in HyperDB so subsequent requests for the same key return the same peers.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install blind-peer-router
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Define a config file at `~/.blind-peer-router/config.json` file with blind peer entries:
|
||||
|
||||
```
|
||||
{
|
||||
"blindPeers": {
|
||||
"<blindPeerKey>": {},
|
||||
"<otherBlindPeerKey>": {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
blind-peer-router run
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
1. The operator starts the service with a list of known blind peer public keys.
|
||||
2. A client sends a `resolve-peers` RPC request with a content key.
|
||||
3. If the key already has an assignment, the stored peers are returned.
|
||||
4. Otherwise the service picks the closest peers by XOR distance, stores the assignment in HyperDB, and returns the peer keys.
|
||||
|
||||
### L limitations
|
||||
|
||||
- **Best-effort persistence in interval mode**: we use periodic flushes, so recent assignments may be lost on unclean shutdown.
|
||||
|
||||
## CLI
|
||||
|
||||
```
|
||||
blind-peer-router run [options]
|
||||
```
|
||||
|
||||
- `--storage|-s [path]`: storage directory (default: `./blind-peer-router`)
|
||||
- `--blind-peer|-b <key>`: blind peer public key in z32 or hex (repeatable, at least one required)
|
||||
- `--replica-count|-r [count]`: number of peers assigned per key (default: `1`)
|
||||
- `--auto-flush [enabled]`: flush on every assignment (`true`/`false`, default: `true`)
|
||||
|
||||
## API
|
||||
|
||||
#### `const service = new BlindPeerRouter(store, swarm, router, opts)`
|
||||
|
||||
Create a new blind peer routing service.
|
||||
|
||||
- `store`: Corestore instance
|
||||
- `swarm`: Hyperswarm instance
|
||||
- `router`: ProtomuxRPCRouter instance (with middleware already applied)
|
||||
- `opts.blindPeerKeys`: array of blind peer public keys (Buffers) — the fixed set of blind peers to assign from
|
||||
- `opts.replicaCount`: number of peers to assign per key (default: `1`, capped to number of blind peers)
|
||||
- `opts.autoFlush`: flush each assignment when `true`; when `false`, flushes are batched by a 1s interval (default: `true`)
|
||||
|
||||
#### `await service.ready()`
|
||||
|
||||
Start the service: opens the database, starts the RPC router, and joins the swarm.
|
||||
|
||||
#### `await service.close()`
|
||||
|
||||
Gracefully shut down the service.
|
||||
|
||||
#### `service.publicKey`
|
||||
|
||||
The swarm public key clients use to connect.
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -1,5 +1,7 @@
|
||||
# Pear
|
||||
|
||||
> **CLI vs runtime (2026)**: The **`pear run`** *shell command* shipped with the Pear CLI is **deprecated** as of Pear **v2.4+** in favor of embedding updates via the **`pear-runtime`** npm package and related tooling (see [`pear-runtime`](../pear/pear-runtime.md) and upstream [`pear/CHANGELOG.md`](https://github.com/holepunchto/pear/blob/main/CHANGELOG.md)). This is **not** the same as the **`pear-run`** npm library used to spawn apps from Node—see [`pear-run`](../pear/pear-run.md).
|
||||
|
||||
Pear is Holepunch's cross-platform application bundler and runtime. It enables building and distributing P2P apps for desktop, mobile, and web with automatic updates.
|
||||
|
||||
**Key Features:**
|
||||
@@ -42,12 +44,13 @@ npm run bootstrap [KEY]
|
||||
|
||||
```sh
|
||||
pear init myapp
|
||||
pear run
|
||||
pear stage
|
||||
pear seed
|
||||
pear release
|
||||
```
|
||||
|
||||
Use **`pear touch`** for link identity; **`package.json` `name` is not used** to derive pear links (Pear **v2.4+**). For multisig releases see **`pear multisig`** and a root **`pear.json`** (see changelog). Prefer **`pear-runtime`** for embeddable runtimes with OTA updates instead of legacy **`pear run`**.
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Keet messenger
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# ready-guard
|
||||
|
||||
**Package**: `ready-guard` · **Version**: v1.0.0 · **License**: Apache-2.0
|
||||
|
||||
## Summary
|
||||
|
||||
Simple signal to do composite resource lifecycles.
|
||||
|
||||
## Upstream
|
||||
|
||||
- Repository: [ready-guard](https://github.com/holepunchto/ready-guard)
|
||||
- Local mirror: `holepunchto_repos/ready-guard`
|
||||
|
||||
## README (from clone)
|
||||
|
||||
# ready-guard
|
||||
|
||||
Like a composite ReadyResource
|
||||
|
||||
```
|
||||
npm install ready-guard
|
||||
```
|
||||
|
||||
`¯\\_(ツ)_/¯`
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const ReadyGuard = require('ready-guard')
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## KB maintenance
|
||||
|
||||
Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.
|
||||
@@ -24,7 +24,7 @@ The original monolithic PROJECT-IDEAS.md file is preserved below for reference.
|
||||
|
||||
<!-- Original content begins -->
|
||||
|
||||
A comprehensive collection of 100+ project ideas for the Holepunch/Hypercore ecosystem, organized by category and complexity. Based on analysis of 554+ repositories.
|
||||
A comprehensive collection of 100+ project ideas for the Holepunch/Hypercore ecosystem, organized by category and complexity. Based on analysis of 600+ repositories.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Research KB maintenance scripts
|
||||
|
||||
|
||||
| Script | Purpose |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `build-module-inventory.mjs` | Writes `module-inventory.json`: each `holepunchto_repos` clone (except dot-dirs and `actions`) mapped to `modules/**/*.md`, plus `package.json` version when present. |
|
||||
| `generate-new-module-stubs.mjs` | One-time / template generator: creates missing `modules/<category>/<repo>.md` from upstream `README.md` + `CHANGELOG.md` + `package.json`. |
|
||||
| `sync-title-semver.mjs` | Tier-C helper: if the **first line** of a doc in `storage/`, `native/`, `utilities/`, or `tooling/` contains `vMAJOR.MINOR.PATCH`, replace it with the clone’s `package.json` version when they differ. |
|
||||
|
||||
|
||||
**Monthly checklist** (see also `dev-diary.md`):
|
||||
|
||||
1. Pull latest `holepunchto_repos` mirrors.
|
||||
2. Run `node scripts/build-module-inventory.mjs` and fix any `undocumentedClones`.
|
||||
3. Run `node scripts/sync-title-semver.mjs`; refresh Tier A/B module pages after semver majors.
|
||||
4. Re-run `npm install` (or `npm ci`) in each `test-projects/`* sample and commit lockfile updates.
|
||||
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Maps holepunchto_repos clone directories to research markdown module files.
|
||||
* Run from anywhere: node scripts/build-module-inventory.mjs
|
||||
*/
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const RESEARCH_ROOT = path.resolve(__dirname, '..')
|
||||
const CLONES_ROOT = path.resolve(RESEARCH_ROOT, '../holepunch_repos/holepunchto_repos')
|
||||
const MODULES_DIR = path.join(RESEARCH_ROOT, 'modules')
|
||||
|
||||
function listClones() {
|
||||
if (!fs.existsSync(CLONES_ROOT)) {
|
||||
console.error('Clones root missing:', CLONES_ROOT)
|
||||
process.exit(1)
|
||||
}
|
||||
return fs
|
||||
.readdirSync(CLONES_ROOT, { withFileTypes: true })
|
||||
.filter(
|
||||
(d) =>
|
||||
d.isDirectory() &&
|
||||
d.name !== 'actions' &&
|
||||
d.name !== '.git' &&
|
||||
!d.name.startsWith('.')
|
||||
)
|
||||
.map((d) => d.name)
|
||||
.sort()
|
||||
}
|
||||
|
||||
function indexModuleDocs() {
|
||||
/** @type {Map<string, string[]>} */
|
||||
const baseToPaths = new Map()
|
||||
if (!fs.existsSync(MODULES_DIR)) return baseToPaths
|
||||
|
||||
function walk(dir) {
|
||||
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const full = path.join(dir, ent.name)
|
||||
if (ent.isDirectory()) walk(full)
|
||||
else if (ent.name.endsWith('.md')) {
|
||||
const base = ent.name.replace(/\.md$/, '')
|
||||
const rel = path.relative(RESEARCH_ROOT, full)
|
||||
const arr = baseToPaths.get(base) || []
|
||||
arr.push(rel)
|
||||
baseToPaths.set(base, arr)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(MODULES_DIR)
|
||||
return baseToPaths
|
||||
}
|
||||
|
||||
function readPackageVersion(cloneName) {
|
||||
const pj = path.join(CLONES_ROOT, cloneName, 'package.json')
|
||||
if (!fs.existsSync(pj)) return null
|
||||
try {
|
||||
const j = JSON.parse(fs.readFileSync(pj, 'utf8'))
|
||||
return j.version || null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
const clones = listClones()
|
||||
const docIndex = indexModuleDocs()
|
||||
|
||||
const entries = clones.map((name) => {
|
||||
const docPaths = docIndex.get(name) || []
|
||||
return {
|
||||
clone: name,
|
||||
packageVersion: readPackageVersion(name),
|
||||
moduleDocPaths: docPaths,
|
||||
documented: docPaths.length > 0
|
||||
}
|
||||
})
|
||||
|
||||
const undocumented = entries.filter((e) => !e.documented).map((e) => e.clone)
|
||||
const basenameMismatchDocs = []
|
||||
const orphanDocBasenames = []
|
||||
for (const [base, paths] of docIndex.entries()) {
|
||||
if (clones.includes(base)) continue
|
||||
if (base === 'rocksdb' && clones.includes('rocksdb-native')) {
|
||||
basenameMismatchDocs.push({
|
||||
base,
|
||||
paths,
|
||||
reason: 'rocksdb.md overlaps rocksdb-native; see modules/native/rocksdb-native.md'
|
||||
})
|
||||
continue
|
||||
}
|
||||
orphanDocBasenames.push({ base, paths, reason: 'no matching clone directory name' })
|
||||
}
|
||||
|
||||
let totalModuleFiles = 0
|
||||
for (const paths of docIndex.values()) totalModuleFiles += paths.length
|
||||
|
||||
const out = {
|
||||
generatedAt: new Date().toISOString(),
|
||||
clonesRoot: CLONES_ROOT,
|
||||
researchRoot: RESEARCH_ROOT,
|
||||
cloneCount: clones.length,
|
||||
uniqueModuleBasenames: docIndex.size,
|
||||
totalModuleFiles,
|
||||
undocumentedClones: undocumented,
|
||||
basenameMismatchDocs,
|
||||
orphanDocBasenames,
|
||||
clones: entries
|
||||
}
|
||||
|
||||
const jsonPath = path.join(__dirname, 'module-inventory.json')
|
||||
fs.writeFileSync(jsonPath, JSON.stringify(out, null, 2))
|
||||
console.log('Wrote', jsonPath)
|
||||
console.log('Clones:', out.cloneCount, '| Undocumented:', undocumented.length)
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Creates module markdown stubs for clones that lack modules/<cat>/<clone>.md.
|
||||
* Reads package.json and README from holepunchto_repos.
|
||||
*/
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const RESEARCH_ROOT = path.resolve(__dirname, '..')
|
||||
const CLONES_ROOT = path.resolve(RESEARCH_ROOT, '../holepunch_repos/holepunchto_repos')
|
||||
const MODULES_DIR = path.join(RESEARCH_ROOT, 'modules')
|
||||
|
||||
/** @type {Record<string, string>} */
|
||||
const CATEGORY = {
|
||||
'_pear-build': 'pear',
|
||||
'bare-addon-java': 'bare',
|
||||
'bare-bluetooth-android': 'bare',
|
||||
'bare-bluetooth-apple': 'bare',
|
||||
'bare-exif': 'bare',
|
||||
'bare-rpc-swift': 'bare',
|
||||
'bare-sidecar-bundle': 'pear',
|
||||
'bare-stdio': 'bare',
|
||||
'bare-tpl': 'bare',
|
||||
'blind-peer-router': 'utilities',
|
||||
'brittle-snapshot': 'tooling',
|
||||
bundlebee: 'pear',
|
||||
'bundlebee-cli': 'pear',
|
||||
cellery: 'pear',
|
||||
'cellery-html': 'pear',
|
||||
'check-npm-maintainers': 'tooling',
|
||||
'cmake-android': 'tooling',
|
||||
'cmake-java': 'tooling',
|
||||
'corestore-snapshot': 'storage',
|
||||
'distributed-drive': 'storage',
|
||||
'electron-devtools-mcp': 'tooling',
|
||||
'electron-forge-maker-appimage': 'tooling',
|
||||
'electron-forge-maker-flatpak': 'tooling',
|
||||
'electron-forge-maker-snap': 'tooling',
|
||||
'gip-remote': 'protocol',
|
||||
'gip-transport': 'protocol',
|
||||
'hello-pear-electron': 'examples',
|
||||
'hrpc-swift': 'protocol',
|
||||
'hyperdht-address': 'network',
|
||||
hypermininet: 'hyper',
|
||||
'hyperschema-swift': 'encoding',
|
||||
libmqjs: 'native',
|
||||
'make-pear-app': 'pear',
|
||||
'msix-manager': 'tooling',
|
||||
'oidc-publishing': 'protocol',
|
||||
'oidc-publishing-sandbox': 'protocol',
|
||||
'pear-ci': 'tooling',
|
||||
'pear-ci-example': 'tooling',
|
||||
'pear-ci-multisig': 'tooling',
|
||||
'pear-multisig-link': 'pear',
|
||||
'pear-runtime': 'pear',
|
||||
'pear-runtime-legacy-storage': 'pear',
|
||||
'pear-runtime-updater': 'pear',
|
||||
'react-native-notifier': 'react-native',
|
||||
'ready-guard': 'utilities',
|
||||
'repo-template': 'tooling',
|
||||
'safe-sodium-buffer': 'crypto',
|
||||
'slack-build-status': 'tooling'
|
||||
}
|
||||
|
||||
function readText(p) {
|
||||
try {
|
||||
return fs.readFileSync(p, 'utf8')
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function readPackage(clone) {
|
||||
const pj = path.join(CLONES_ROOT, clone, 'package.json')
|
||||
if (!fs.existsSync(pj)) return null
|
||||
try {
|
||||
return JSON.parse(readText(pj))
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function excerptReadme(clone, maxLen = 3500) {
|
||||
const r = path.join(CLONES_ROOT, clone, 'README.md')
|
||||
let t = readText(r).trim()
|
||||
if (!t) return '_No README.md in clone; see upstream repository._'
|
||||
if (t.length > maxLen) t = t.slice(0, maxLen) + '\n\n…(truncated; see full README in repo)…'
|
||||
return t
|
||||
}
|
||||
|
||||
function changelogHead(clone, maxLen = 2500) {
|
||||
const c = path.join(CLONES_ROOT, clone, 'CHANGELOG.md')
|
||||
let t = readText(c).trim()
|
||||
if (!t) return ''
|
||||
if (t.length > maxLen) t = t.slice(0, maxLen) + '\n\n…(truncated)…'
|
||||
return `## Recent changelog (excerpt)\n\n${t}`
|
||||
}
|
||||
|
||||
function buildDoc(clone) {
|
||||
const pkg = readPackage(clone)
|
||||
const version = pkg?.version ? `v${pkg.version}` : 'version n/a'
|
||||
const desc = pkg?.description || 'Holepunch ecosystem component'
|
||||
const repoUrl =
|
||||
pkg?.repository?.url?.replace(/^git\+/, '').replace(/\.git$/, '') ||
|
||||
`https://github.com/holepunchto/${clone}`
|
||||
const license = pkg?.license || 'see repository'
|
||||
|
||||
const body = [
|
||||
`# ${clone}`,
|
||||
'',
|
||||
`**Package**: \`${pkg?.name || clone}\` · **Version**: ${version} · **License**: ${license}`,
|
||||
'',
|
||||
'## Summary',
|
||||
'',
|
||||
desc + '.',
|
||||
'',
|
||||
'## Upstream',
|
||||
'',
|
||||
`- Repository: [${clone}](${repoUrl})`,
|
||||
`- Local mirror: \`holepunchto_repos/${clone}\``,
|
||||
'',
|
||||
'## README (from clone)',
|
||||
'',
|
||||
excerptReadme(clone),
|
||||
''
|
||||
]
|
||||
|
||||
const ch = changelogHead(clone)
|
||||
if (ch) body.push(ch, '')
|
||||
|
||||
body.push('## KB maintenance', '', 'Generated by `scripts/generate-new-module-stubs.mjs`. Refresh from upstream when APIs change.', '')
|
||||
|
||||
return body.join('\n')
|
||||
}
|
||||
|
||||
function main() {
|
||||
const invPath = path.join(__dirname, 'module-inventory.json')
|
||||
const inv = JSON.parse(readText(invPath))
|
||||
const undocumented = inv.undocumentedClones
|
||||
let n = 0
|
||||
for (const clone of undocumented) {
|
||||
const cat = CATEGORY[clone]
|
||||
if (!cat) {
|
||||
console.error('Missing CATEGORY for', clone)
|
||||
process.exit(1)
|
||||
}
|
||||
const dir = path.join(MODULES_DIR, cat)
|
||||
fs.mkdirSync(dir, { recursive: true })
|
||||
const outPath = path.join(dir, `${clone}.md`)
|
||||
fs.writeFileSync(outPath, buildDoc(clone))
|
||||
n++
|
||||
console.log('Wrote', path.relative(RESEARCH_ROOT, outPath))
|
||||
}
|
||||
console.log('Total', n)
|
||||
}
|
||||
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Tier-C helper: where the first line of a module doc contains vMAJOR.MINOR.PATCH,
|
||||
* replace that semver with the version from holepunchto_repos/<basename>/package.json
|
||||
* when they differ. Only touches modules under storage, native, utilities, tooling.
|
||||
*/
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const RESEARCH_ROOT = path.resolve(__dirname, '..')
|
||||
const MODULES = path.join(RESEARCH_ROOT, 'modules')
|
||||
const CLONES = path.resolve(RESEARCH_ROOT, '../holepunch_repos/holepunchto_repos')
|
||||
const SUBDIRS = ['storage', 'native', 'utilities', 'tooling']
|
||||
|
||||
function readJson(p) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(p, 'utf8'))
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
const changes = []
|
||||
for (const sub of SUBDIRS) {
|
||||
const dir = path.join(MODULES, sub)
|
||||
if (!fs.existsSync(dir)) continue
|
||||
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
if (!ent.isFile() || !ent.name.endsWith('.md')) continue
|
||||
const base = ent.name.replace(/\.md$/, '')
|
||||
const pj = path.join(CLONES, base, 'package.json')
|
||||
if (!fs.existsSync(pj)) continue
|
||||
const pkg = readJson(pj)
|
||||
if (!pkg?.version) continue
|
||||
const want = pkg.version
|
||||
const mdPath = path.join(dir, ent.name)
|
||||
const raw = fs.readFileSync(mdPath, 'utf8')
|
||||
const lines = raw.split('\n')
|
||||
if (lines.length < 1) continue
|
||||
const first = lines[0]
|
||||
const m = first.match(/v(\d+\.\d+\.\d+)/)
|
||||
if (!m) continue
|
||||
if (m[1] === want) continue
|
||||
lines[0] = first.replace(m[0], `v${want}`)
|
||||
fs.writeFileSync(mdPath, lines.join('\n'))
|
||||
changes.push({ file: path.relative(RESEARCH_ROOT, mdPath), from: m[1], to: want })
|
||||
}
|
||||
}
|
||||
console.log(JSON.stringify({ updated: changes.length, changes }, null, 2))
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,11 @@
|
||||
# Test projects
|
||||
|
||||
Small runnable samples for the KB. Each folder is a standalone Node project.
|
||||
|
||||
```bash
|
||||
cd test-projects/<name>
|
||||
npm install
|
||||
node index.js
|
||||
```
|
||||
|
||||
Do not commit `node_modules/`; lockfiles (`package-lock.json`) should reflect current dependency ranges in each `package.json`.
|
||||
@@ -20,17 +20,16 @@ if (mode === 'writer1') localWriterSeed = WRITER1_KEY_SEED
|
||||
else if (mode === 'writer2') localWriterSeed = WRITER2_KEY_SEED
|
||||
const localWriterKey = localWriterSeed ? crypto.createHash('sha256').update(localWriterSeed).digest() : null
|
||||
|
||||
const WRITER1_KEY = crypto.createHash('sha256').update(WRITER1_KEY_SEED).digest()
|
||||
const WRITER2_KEY = crypto.createHash('sha256').update(WRITER2_KEY_SEED).digest()
|
||||
|
||||
|
||||
console.log('Fixed base key:', baseKey.toString('hex'))
|
||||
console.log('Writer1 key:', WRITER1_KEY.toString('hex'))
|
||||
console.log('Writer2 key:', WRITER2_KEY.toString('hex'))
|
||||
|
||||
console.log(`Mode: ${mode}, storage: ${storage}`)
|
||||
|
||||
async function main() {
|
||||
const corestore = new Corestore(storage, { namespace: ns })
|
||||
|
||||
|
||||
function open (store, host) {
|
||||
return store.get({ name: 'merged-todos', valueEncoding: 'json' })
|
||||
}
|
||||
@@ -41,8 +40,7 @@ async function apply (nodes, view, host) {
|
||||
if (value === null) continue
|
||||
if (value.bootstrap && value.password === 'autobasetestsecret') {
|
||||
console.log('Bootstrap: adding writers')
|
||||
await host.addWriter(WRITER1_KEY, { indexer: true })
|
||||
await host.addWriter(WRITER2_KEY, { indexer: true })
|
||||
console.log('Bootstrap: bootstrap signal received')
|
||||
continue
|
||||
}
|
||||
if (value.addWriter) {
|
||||
@@ -64,7 +62,6 @@ console.log('Discovery key:', base.discoveryKey.toString('hex'))
|
||||
console.log('Local core key:', base.local.key.toString('hex'))
|
||||
base.on('writable', () => console.log('Event: became writable'))
|
||||
base.on('update', () => console.log('Update event, length:', base.length, 'writable:', base.writable))
|
||||
console.log('Discovery key:', base.discoveryKey.toString('hex'))
|
||||
|
||||
const swarm = new Hyperswarm()
|
||||
const discovery = swarm.join(base.discoveryKey, { server: true, client: true })
|
||||
@@ -83,6 +80,9 @@ base.on('update', () => console.log('Update event, length:', base.length, 'writa
|
||||
console.log('Sending bootstrap signal...')
|
||||
await base.append({ bootstrap: true, password: 'autobasetestsecret' }, { optimistic: true })
|
||||
console.log('Bootstrap signal sent')
|
||||
console.log('Adding local writer...')
|
||||
await base.append({addWriter: base.local.key}, {optimistic: true})
|
||||
console.log('Local writer added')
|
||||
}
|
||||
// Read loop always
|
||||
const readInterval = setInterval(async () => {
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
../hyperdht/bin.js
|
||||
-991
@@ -1,991 +0,0 @@
|
||||
{
|
||||
"name": "hyperbee-chat",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/@hyperswarm/secret-stream": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@hyperswarm/secret-stream/-/secret-stream-6.9.1.tgz",
|
||||
"integrity": "sha512-xb0S5y3YJwBakD77JOGBHlBxdp63mHClZoXBYoLv+9wH8e054ESKlmQptWqjJK5dv5VMUIVYOJB4MaOpB0JdGw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.1.0",
|
||||
"hypercore-crypto": "^3.3.1",
|
||||
"noise-curve-ed": "^2.0.1",
|
||||
"noise-handshake": "^4.0.0",
|
||||
"sodium-secretstream": "^1.1.0",
|
||||
"sodium-universal": "^5.0.0",
|
||||
"streamx": "^2.14.0",
|
||||
"timeout-refresh": "^2.0.0",
|
||||
"unslab": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/adaptive-timeout": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/adaptive-timeout/-/adaptive-timeout-1.0.1.tgz",
|
||||
"integrity": "sha512-+seGiBtHqbnyZ0Quq/ZGxxwP66153WBABawa07/QeyuPFzbduPBjiGQAyCiriiLDzt3dkbMBskSlfqtRwblK8Q==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"xache": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/b4a": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
|
||||
"integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"react-native-b4a": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-native-b4a": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-addon-resolve": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz",
|
||||
"integrity": "sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-module-resolve": "^1.10.0",
|
||||
"bare-semver": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-url": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-url": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-ansi-escapes": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/bare-ansi-escapes/-/bare-ansi-escapes-2.2.3.tgz",
|
||||
"integrity": "sha512-02ES4/E2RbrtZSnHJ9LntBhYkLA6lPpSEeP8iqS3MccBIVhVBlEmruF1I7HZqx5Q8aiTeYfQVeqmrU9YO2yYoQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-stream": "^2.6.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-buffer": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-buffer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-assert": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bare-assert/-/bare-assert-1.2.0.tgz",
|
||||
"integrity": "sha512-c6uvgvTJBspTDxtVnPgrBKmLgcpW3Fp72NVKDLg6oT4QjQbhGtvrkHMhGYMK1sh4vjBHOBmuUalyt9hSzV37fQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-inspect": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/bare-events": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
|
||||
"integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"bare-abort-controller": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-abort-controller": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-fs": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz",
|
||||
"integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-events": "^2.5.4",
|
||||
"bare-path": "^3.0.0",
|
||||
"bare-stream": "^2.6.4",
|
||||
"bare-url": "^2.2.2",
|
||||
"fast-fifo": "^1.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"bare": ">=1.16.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-buffer": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-buffer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-inspect": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/bare-inspect/-/bare-inspect-3.1.4.tgz",
|
||||
"integrity": "sha512-jfW5KRA84o3REpI6Vr4nbvMn+hqVAw8GU1mMdRwUsY5yJovQamxYeKGVKGqdzs+8ZbG4jRzGUXP/3Ji/DnqfPg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-ansi-escapes": "^2.1.0",
|
||||
"bare-type": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"bare": ">=1.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bare-module-resolve": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz",
|
||||
"integrity": "sha512-hbmAPyFpEq8FoZMd5sFO3u6MC5feluWoGE8YKlA8fCrl6mNtx68Wjg4DTiDJcqRJaovTvOYKfYngoBUnbaT7eg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-semver": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-url": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-url": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-os": {
|
||||
"version": "3.8.7",
|
||||
"resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.7.tgz",
|
||||
"integrity": "sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"bare": ">=1.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bare-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
|
||||
"integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-os": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/bare-semver": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.3.tgz",
|
||||
"integrity": "sha512-HS/A30bi2+PiRJfU6R4+Kp+6KeLSCSByjYM2iiobOKzLAvtu1CT+S8xWfiU7wz0erknjkUoC+yXy108tzIuP5Q==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/bare-stream": {
|
||||
"version": "2.13.0",
|
||||
"resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.0.tgz",
|
||||
"integrity": "sha512-3zAJRZMDFGjdn+RVnNpF9kuELw+0Fl3lpndM4NcEOhb9zwtSo/deETfuIwMSE5BXanA0FrN1qVjffGwAg2Y7EA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"streamx": "^2.25.0",
|
||||
"teex": "^1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-abort-controller": "*",
|
||||
"bare-buffer": "*",
|
||||
"bare-events": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-abort-controller": {
|
||||
"optional": true
|
||||
},
|
||||
"bare-buffer": {
|
||||
"optional": true
|
||||
},
|
||||
"bare-events": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-type": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bare-type/-/bare-type-1.1.0.tgz",
|
||||
"integrity": "sha512-LdtnnEEYldOc87Dr4GpsKnStStZk3zfgoEMXy8yvEZkXrcCv9RtYDrUYWFsBQHtaB0s1EUWmcvS6XmEZYIj3Bw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"bare": ">=1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bare-url": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.1.tgz",
|
||||
"integrity": "sha512-fZapLWNB25gS+etK27NV9KgBNXgo2yeYHuj+OyPblQd6GYAE3JVy6aKxszMV5jhGGFwraXQKA5fldvf3lMyEqw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/big-sparse-array": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/big-sparse-array/-/big-sparse-array-1.0.3.tgz",
|
||||
"integrity": "sha512-6RjV/3mSZORlMdpUaQ6rUSpG637cZm0//E54YYGtQg1c1O+AbZP8UTdJ/TchsDZcTVLmyWZcseBfp2HBeXUXOQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bits-to-bytes": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/bits-to-bytes/-/bits-to-bytes-1.3.0.tgz",
|
||||
"integrity": "sha512-OJoHTpFXS9bXHBCekGTByf3MqM8CGblBDIduKQeeVVeiU9dDWywSSirXIBYGgg3d1zbVuvnMa1vD4r6PA0kOKg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"b4a": "^1.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/blind-relay": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/blind-relay/-/blind-relay-1.4.0.tgz",
|
||||
"integrity": "sha512-6xt7fDfCs6eGmNNym6I9N42jmjcMQn2qwwOVnkP9ZnrkXFk6c4/tdO1xqRmDEzKzV8gigd+DVdCUG/RUYnen7Q==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.4",
|
||||
"bare-events": "^2.2.0",
|
||||
"bits-to-bytes": "^1.3.0",
|
||||
"compact-encoding": "^2.12.0",
|
||||
"compact-encoding-bitfield": "^1.0.0",
|
||||
"protomux": "^3.5.1",
|
||||
"sodium-universal": "^5.0.0",
|
||||
"streamx": "^2.15.1"
|
||||
}
|
||||
},
|
||||
"node_modules/bogon": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bogon/-/bogon-1.2.0.tgz",
|
||||
"integrity": "sha512-FqOBr/1VMzCOsoJd+fzNUMarUYki2+TKt07A2+xaulsNx4r53iJ7MV5k0jbqg7W2U0CsLqxCZOrFibdG6h6HSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"compact-encoding": "^2.11.0",
|
||||
"compact-encoding-net": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/codecs": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/codecs/-/codecs-3.1.0.tgz",
|
||||
"integrity": "sha512-Dqx8NwvBvnMeuPQdVKy/XEF71igjR5apxBvCGeV0pP1tXadOiaLvDTXt7xh+/5wI1ASB195mXQGJbw3Ml4YDWQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.3"
|
||||
}
|
||||
},
|
||||
"node_modules/compact-encoding": {
|
||||
"version": "2.19.2",
|
||||
"resolved": "https://registry.npmjs.org/compact-encoding/-/compact-encoding-2.19.2.tgz",
|
||||
"integrity": "sha512-/YjhHQE/5L4F7l5Bht69dRbP9RV6zoJPeowi8bMKQxNKe3Nh6hOY8pBGoVE9fz5GaWfEd8fWJ2aU9sB4KZuMYg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/compact-encoding-bitfield": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/compact-encoding-bitfield/-/compact-encoding-bitfield-1.0.0.tgz",
|
||||
"integrity": "sha512-3nMVKUg+PF72UHfainmCL8uKvyWfxsjqOtUY+HiMPGLPCTjnwzoKfFAMo1Ad7nwTPdjBqtGK5b3BOFTFW4EBTg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"compact-encoding": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/compact-encoding-net": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/compact-encoding-net/-/compact-encoding-net-1.2.0.tgz",
|
||||
"integrity": "sha512-LVXpNpF7PGQeHRVVLGgYWzuVoYAaDZvKUsUxRioGfkotzvOh4AzoQF1HBH3zMNaSnx7gJXuUr3hkjnijaH/Eng==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"compact-encoding": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/corestore": {
|
||||
"version": "7.9.2",
|
||||
"resolved": "https://registry.npmjs.org/corestore/-/corestore-7.9.2.tgz",
|
||||
"integrity": "sha512-dyIktVSVLu0skZ1UM4yODbNbZ46dBpTHypzwlwET1btVuS3YIf66Zz8Tx8h3Xa8nbLO2USGqrYtvPYzSRj2wCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.7",
|
||||
"hypercore": "^11.19.0",
|
||||
"hypercore-crypto": "^3.4.2",
|
||||
"hypercore-errors": "^1.4.0",
|
||||
"hypercore-id-encoding": "^1.3.0",
|
||||
"ready-resource": "^1.1.1",
|
||||
"sodium-universal": "^5.0.1",
|
||||
"which-runtime": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/debounceify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debounceify/-/debounceify-1.1.0.tgz",
|
||||
"integrity": "sha512-eKuHDVfJVg+u/0nPy8P+fhnLgbyuTgVxuCRrS/R7EpDSMMkBDgSes41MJtSAY1F1hcqfHz3Zy/qpqHHIp/EhdA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/device-file": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/device-file/-/device-file-2.3.1.tgz",
|
||||
"integrity": "sha512-bmON44lwxJPle9N2OcH4tqM44pMGZKT8G6OkzXkz0urvqQ9LKkoQdTS6w0ztYfmLdUE27R4UUmx0+y2gEz4Jug==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.7",
|
||||
"bare-fs": "^4.0.1",
|
||||
"bare-path": "^3.0.0",
|
||||
"fd-lock": "^2.1.0",
|
||||
"fs-native-extensions": "^1.4.0",
|
||||
"ready-resource": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dht-rpc": {
|
||||
"version": "6.26.4",
|
||||
"resolved": "https://registry.npmjs.org/dht-rpc/-/dht-rpc-6.26.4.tgz",
|
||||
"integrity": "sha512-bMI625c13DXaiYN8vHEFmcM4CIauwK1SJgOMWAAqsXhsKXO8WCdp0fgYwTHH40cBB6J9MkDXPa2f79Vj5Ah1iA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"adaptive-timeout": "^1.0.1",
|
||||
"b4a": "^1.6.1",
|
||||
"bare-events": "^2.2.0",
|
||||
"compact-encoding": "^2.11.0",
|
||||
"compact-encoding-net": "^1.2.0",
|
||||
"fast-fifo": "^1.1.0",
|
||||
"kademlia-routing-table": "^1.0.1",
|
||||
"nat-sampler": "^1.0.1",
|
||||
"sodium-universal": "^5.0.0",
|
||||
"streamx": "^2.13.2",
|
||||
"time-ordered-set": "^2.0.0",
|
||||
"udx-native": "^1.5.3"
|
||||
}
|
||||
},
|
||||
"node_modules/events-universal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
|
||||
"integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-events": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-fifo": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
||||
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fd-lock": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-2.1.1.tgz",
|
||||
"integrity": "sha512-H3VkcWFl39Rk0xBokDcUyBcVs6VrYTUo/DhDWMzJOF99wXWDAvmvq/GlLTS2NTehsznZhp3fXVyrtB2ldDXhwg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-fs": "^4.5.0",
|
||||
"fs-native-extensions": "^1.4.4",
|
||||
"ready-resource": "^1.2.0",
|
||||
"resource-on-exit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/flat-tree": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/flat-tree/-/flat-tree-1.13.0.tgz",
|
||||
"integrity": "sha512-fT3HIuCPwHhFgJ20QYzDHgUG0zMmFg5cHvFiFo5h+QMSJ28TihsEVY0f8HGliuO+pOzmvjMx1odToeaEWkTnyQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fs-native-extensions": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-native-extensions/-/fs-native-extensions-1.5.0.tgz",
|
||||
"integrity": "sha512-nuZLFm9mGCxvyi7Llww/J4OyifKCS21nEUTAmnlTZp3FObPOvA32aCedCmt4Z+8yk+caqfClNaSCfn/P7T7FLQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"require-addon": "^1.1.0",
|
||||
"which-runtime": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/generate-object-property": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-2.0.0.tgz",
|
||||
"integrity": "sha512-KwuURPyqn2Mz8DdV29pJwQu0Y7tcsbkULr82eeOcY/ZllFK6I9Wm8dsRByIu7CKWlFi9BdW1b3mcXMp/kQBQsw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-property": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/generate-string": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/generate-string/-/generate-string-1.0.1.tgz",
|
||||
"integrity": "sha512-IfTY0dKZM43ACyGvXkbG7De7WY7MxTS5VO6Juhe8oJKpCmrYYXoqp/cJMskkpi0k9H8wuXq0H+eI898/BCqvXg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/hyperbee": {
|
||||
"version": "2.27.3",
|
||||
"resolved": "https://registry.npmjs.org/hyperbee/-/hyperbee-2.27.3.tgz",
|
||||
"integrity": "sha512-PXURH2U4juUZyJRKHTrY5z1zX851pmI1Q0jfv5F/hCIErDt/ND8jOZuxc3hfOLM9f0W3qJEDTMlV5AJBkVPy8w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.0",
|
||||
"codecs": "^3.0.0",
|
||||
"debounceify": "^1.0.0",
|
||||
"hypercore-errors": "^1.0.0",
|
||||
"mutexify": "^1.4.0",
|
||||
"protocol-buffers-encodings": "^1.2.0",
|
||||
"rache": "^1.0.0",
|
||||
"ready-resource": "^1.0.0",
|
||||
"resolve-reject-promise": "^1.1.0",
|
||||
"safety-catch": "^1.0.2",
|
||||
"streamx": "^2.12.4",
|
||||
"unslab": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hypercore": {
|
||||
"version": "11.28.1",
|
||||
"resolved": "https://registry.npmjs.org/hypercore/-/hypercore-11.28.1.tgz",
|
||||
"integrity": "sha512-d8jqUilG7Gri8wT+sRdkFTYRPMHGyvBz/NCYHf5rX7+LoivRNRxQm5nWChT7caiUKbcsDak6h7IiEQ5wbD1wCg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@hyperswarm/secret-stream": "^6.0.0",
|
||||
"b4a": "^1.1.0",
|
||||
"bare-events": "^2.2.0",
|
||||
"big-sparse-array": "^1.0.3",
|
||||
"compact-encoding": "^2.11.0",
|
||||
"fast-fifo": "^1.3.0",
|
||||
"flat-tree": "^1.9.0",
|
||||
"hypercore-crypto": "^3.2.1",
|
||||
"hypercore-errors": "^1.5.0",
|
||||
"hypercore-id-encoding": "^1.2.0",
|
||||
"hypercore-storage": "^2.8.0",
|
||||
"is-options": "^1.0.1",
|
||||
"nanoassert": "^2.0.0",
|
||||
"protomux": "^3.5.0",
|
||||
"quickbit-universal": "^2.2.0",
|
||||
"random-array-iterator": "^1.0.0",
|
||||
"safety-catch": "^1.0.1",
|
||||
"sodium-universal": "^5.0.1",
|
||||
"streamx": "^2.12.4",
|
||||
"unslab": "^1.3.0",
|
||||
"z32": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hypercore-crypto": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/hypercore-crypto/-/hypercore-crypto-3.6.1.tgz",
|
||||
"integrity": "sha512-ltIz2uDwy9pO/ZGTvqcjzyBkvt6O4cVm4r/nNxh0GFs/RbQtqP/i4wCvLEdmU7ptgtnw7fI67WYD1aHPuv4OVA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.6",
|
||||
"compact-encoding": "^2.15.0",
|
||||
"sodium-universal": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hypercore-errors": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/hypercore-errors/-/hypercore-errors-1.5.0.tgz",
|
||||
"integrity": "sha512-5KQ/SuDxsvet+7qWA35Ay6zdD9WyAHQoyWHGcPUTbmJBd300gvNIJoi3oma7kp4TTCSzii6qYumNZe/s0j/saQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"hypercore-id-encoding": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hypercore-id-encoding": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/hypercore-id-encoding/-/hypercore-id-encoding-1.3.0.tgz",
|
||||
"integrity": "sha512-W6sHdGo5h7LXEsoWfKf/KfuROZmZRQDlGqJF2EPHW+noCK66Vvr0+zE6cL0vqQi18s0kQPeN7Sq3QyR0Ytc2VQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.5.3",
|
||||
"z32": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hypercore-storage": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/hypercore-storage/-/hypercore-storage-2.8.0.tgz",
|
||||
"integrity": "sha512-s35HllFMYvrkSHvkIIklVFmCI/bRVNO7H3pi4mKvWl0XLyhGGGM+NtJ7fpsh82oPRCmL9XtMRO+pT6LiMAO8MA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.7",
|
||||
"bare-fs": "^4.0.1",
|
||||
"bare-path": "^3.0.0",
|
||||
"compact-encoding": "^2.16.0",
|
||||
"device-file": "^2.1.2",
|
||||
"flat-tree": "^1.12.1",
|
||||
"hypercore-crypto": "^3.4.2",
|
||||
"hyperschema": "^1.7.0",
|
||||
"index-encoder": "^3.3.2",
|
||||
"resolve-reject-promise": "^1.0.0",
|
||||
"rocksdb-native": "^3.11.0",
|
||||
"scope-lock": "^1.2.4",
|
||||
"streamx": "^2.21.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hyperdht": {
|
||||
"version": "6.30.0",
|
||||
"resolved": "https://registry.npmjs.org/hyperdht/-/hyperdht-6.30.0.tgz",
|
||||
"integrity": "sha512-LkfeAFVnOIvOpr2ILtJ38CzPgXmye7jXDS12xndVKfNoxzIrM0GonY+Bz5lHutoc08ZbT3Olr/w2NSeq5Pj0Ng==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@hyperswarm/secret-stream": "^6.6.2",
|
||||
"b4a": "^1.3.1",
|
||||
"bare-events": "^2.2.0",
|
||||
"blind-relay": "^1.3.0",
|
||||
"bogon": "^1.0.0",
|
||||
"compact-encoding": "^2.4.1",
|
||||
"dht-rpc": "^6.15.1",
|
||||
"hypercore-crypto": "^3.3.0",
|
||||
"hypercore-id-encoding": "^1.2.0",
|
||||
"hyperdht-address": "^1.0.1",
|
||||
"noise-curve-ed": "^2.0.0",
|
||||
"noise-handshake": "^4.0.0",
|
||||
"record-cache": "^1.1.1",
|
||||
"safety-catch": "^1.0.1",
|
||||
"signal-promise": "^1.0.3",
|
||||
"sodium-universal": "^5.0.1",
|
||||
"streamx": "^2.16.1",
|
||||
"unslab": "^1.3.0",
|
||||
"xache": "^1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"hyperdht": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/hyperdht-address": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hyperdht-address/-/hyperdht-address-1.0.1.tgz",
|
||||
"integrity": "sha512-v817eJkhryWNtMGQHLxVo6jtfEeIV9k429fRUWUKkp1bm+3/rzH8r5BFef9VT7Jq4Tvgt0Gw11FV32CacsqMZA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"compact-encoding": "^2.19.0",
|
||||
"hyperschema": "^1.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hyperschema": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/hyperschema/-/hyperschema-1.20.1.tgz",
|
||||
"integrity": "sha512-7gnvaTNUs8FqdrU3NNE6nzhOneGyDlUlpROu9YFlHA61fE8ppKKf2gLZjZjsx/enNt+VFN4ITxy8ijypfyWBLw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-fs": "^4.0.1",
|
||||
"compact-encoding": "^2.19.0",
|
||||
"generate-object-property": "^2.0.0",
|
||||
"generate-string": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hyperswarm": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/hyperswarm/-/hyperswarm-4.17.0.tgz",
|
||||
"integrity": "sha512-oe86sK961Ueg7rvDN/veFwG8xH+Iv6vObPhGDkPJcDVxk/NduW41ZhAcVDnHzRbm7S0eLU7WaDUvehOYoKSpRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.3.1",
|
||||
"bare-events": "^2.2.0",
|
||||
"hyperdht": "^6.21.0",
|
||||
"safety-catch": "^1.0.2",
|
||||
"shuffled-priority-queue": "^2.1.0",
|
||||
"streamx": "^2.22.1",
|
||||
"unslab": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/index-encoder": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/index-encoder/-/index-encoder-3.5.0.tgz",
|
||||
"integrity": "sha512-idZ1cxtZz2dRV6rUiaP9Xo99UjXbSzjcMacoQmxUMu/A7fEQcNPngvwDJYeWelQUS5XFlY71/or70lKn6XnwbQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-options": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-options/-/is-options-1.0.2.tgz",
|
||||
"integrity": "sha512-u+Ai74c8Q74aS8BuHwPdI1jptGOT1FQXgCq8/zv0xRuE+wRgSMEJLj8lVO8Zp9BeGb29BXY6AsNPinfqjkr7Fg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/is-property": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/kademlia-routing-table": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/kademlia-routing-table/-/kademlia-routing-table-1.0.6.tgz",
|
||||
"integrity": "sha512-Ve6jwIlUCYvUzBnXnzVRHDZCFgXURW9gmF3r7n05kZs/2rNbLHXwGdcq0qIaSwdmJCvtosgR4JensnVU65hzNQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bare-events": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mutexify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.4.0.tgz",
|
||||
"integrity": "sha512-pbYSsOrSB/AKN5h/WzzLRMFgZhClWccf2XIB4RSMC8JbquiB0e0/SH5AIfdQMdyHmYtv4seU7yV/TvAwPLJ1Yg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"queue-tick": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoassert": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz",
|
||||
"integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/nat-sampler": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/nat-sampler/-/nat-sampler-1.0.1.tgz",
|
||||
"integrity": "sha512-yQvyNN7xbqR8crTKk3U8gRgpcV1Az+vfCEijiHu9oHHsnIl8n3x+yXNHl42M6L3czGynAVoOT9TqBfS87gDdcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/noise-curve-ed": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/noise-curve-ed/-/noise-curve-ed-2.1.0.tgz",
|
||||
"integrity": "sha512-zAzJx+VwZM3w6EA1hTmDhJfvAnCeBQn/1FAeZ0LtGxCcCtlAK/uJXQVF/eDVUOaAZ286lHlx77WJ+qj9SmsRRg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"b4a": "^1.1.0",
|
||||
"nanoassert": "^2.0.0",
|
||||
"sodium-universal": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/noise-handshake": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/noise-handshake/-/noise-handshake-4.2.0.tgz",
|
||||
"integrity": "sha512-9O/VTNX/E2/AToyMTTDU0J/4WhaXMTdqc2DHs9vf+snoZ0cenSBq0dNYTVV1snYYEkmo6QeRrYMxtqtoYnY+LA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.1.0",
|
||||
"nanoassert": "^2.0.0",
|
||||
"sodium-universal": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/protocol-buffers-encodings": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/protocol-buffers-encodings/-/protocol-buffers-encodings-1.2.0.tgz",
|
||||
"integrity": "sha512-daeNPuKh1NlLD1uDfbLpD+xyUTc07nEtfHwmBZmt/vH0B7VOM+JOCOpDcx9ZRpqHjAiIkGqyTDi+wfGSl17R9w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.0",
|
||||
"signed-varint": "^2.0.1",
|
||||
"varint": "5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/protomux": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/protomux/-/protomux-3.10.1.tgz",
|
||||
"integrity": "sha512-jgBqx8ZyaBWea/DFG4eOu1scOaeBwcnagiRC1XFVrjeGt7oAb0Pk5udPpBUpJ4DJBRjra50jD6YcZiQQTRqaaA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.3.1",
|
||||
"compact-encoding": "^2.5.1",
|
||||
"queue-tick": "^1.0.0",
|
||||
"safety-catch": "^1.0.1",
|
||||
"unslab": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-tick": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
|
||||
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/quickbit-native": {
|
||||
"version": "2.4.8",
|
||||
"resolved": "https://registry.npmjs.org/quickbit-native/-/quickbit-native-2.4.8.tgz",
|
||||
"integrity": "sha512-FcCcqI+nIAWGknqhtrYT5TSD7t/N+Xd8ctM+2PrIIBuwOi5hx0SxAvuPtzLIEMfT/2h9+fhBakUe2uALOHX6yw==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"require-addon": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/quickbit-universal": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/quickbit-universal/-/quickbit-universal-2.2.0.tgz",
|
||||
"integrity": "sha512-w02i1R8n7+6pEKTud8DfF8zbFY9o7RtPlUc3jWbtCkDKvhbx/AvV7oNnz4/TcmsPGpSJS+fq5Ud6RH6+YPvSGg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.0",
|
||||
"simdle-universal": "^1.1.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"quickbit-native": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/rache/-/rache-1.0.0.tgz",
|
||||
"integrity": "sha512-e0k0g0w/8jOCB+7YqCIlOa+OJ38k0wrYS4x18pMSmqOvLKoyhmMhmQyCcvfY6VaP8D75cqkEnlakXs+RYYLqNg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/random-array-iterator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/random-array-iterator/-/random-array-iterator-1.0.0.tgz",
|
||||
"integrity": "sha512-u7xCM93XqKEvPTP6xZp2ehttcAemKnh73oKNf1FvzuVCfpt6dILDt1Kxl1LeBjm2iNIeR49VGFhy4Iz3yOun+Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ready-resource": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ready-resource/-/ready-resource-1.2.0.tgz",
|
||||
"integrity": "sha512-nfcco/8iAFV0M+2PYnmIc+/xY0iRb35d42HFHQ7AfjulbGEAFa+XWpByfwSyeVeiBoMLLFVMv1HixxNCqzSQ1g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bare-events": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/record-cache": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/record-cache/-/record-cache-1.2.0.tgz",
|
||||
"integrity": "sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/refcounter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/refcounter/-/refcounter-1.0.0.tgz",
|
||||
"integrity": "sha512-1WosVzUy0kPUaPMEtlNDwm99UsteALIhXXR8rerELoa63WkYIXAl0hxgwPFrIYBRWZPGUyekQ04FRtPJ7dHk9w==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/require-addon": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz",
|
||||
"integrity": "sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-addon-resolve": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"bare": ">=1.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-reject-promise": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-reject-promise/-/resolve-reject-promise-1.1.0.tgz",
|
||||
"integrity": "sha512-LWsTOA91AqzBTjSGgX79Tc130pwcBK6xjpJEO+qRT5IKZ6bGnHKcc8QL3upUBcWuU8OTIDzKK2VNSwmmlqvAVg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resource-on-exit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resource-on-exit/-/resource-on-exit-1.0.0.tgz",
|
||||
"integrity": "sha512-ViJwJAknCkLRJRPR+9SISQQ7R5eRgtdIHLJsM2hHx1MweAJbJxJ5XnMjjq0Lc7ZGv44ufzAqds1nKxiVkdy4ag==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/rocksdb-native": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/rocksdb-native/-/rocksdb-native-3.15.0.tgz",
|
||||
"integrity": "sha512-czYx0hOzKAy+HYmJROZm7thvJ1tHFWHNkGI3nomumXWzrJghJdrWo4MIhehGX4OTff0lnOCoB2zu6ekzIKY0rQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"compact-encoding": "^2.15.0",
|
||||
"ready-resource": "^1.0.0",
|
||||
"refcounter": "^1.0.0",
|
||||
"require-addon": "^1.0.2",
|
||||
"resolve-reject-promise": "^1.1.0",
|
||||
"signal-promise": "^1.0.3",
|
||||
"streamx": "^2.16.1"
|
||||
},
|
||||
"engines": {
|
||||
"bare": ">=1.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safety-catch": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/safety-catch/-/safety-catch-1.0.3.tgz",
|
||||
"integrity": "sha512-Zq+J1TefpoEq/HTUabo0YXX5MNvttjWYODGohgPBO2jfko8Wqx3JYMgE823szDFVamdH5PlpByvfiWScTdSYDA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scope-lock": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/scope-lock/-/scope-lock-1.2.4.tgz",
|
||||
"integrity": "sha512-BpSd8VCuCxW9ZitcdIC/vjs3gMaP9bRBL5nkHcyfX2VrS52n13/rHuBA2xJ/S/4DPuRdAO/Bk8pWd8eD/gHCIA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/shuffled-priority-queue": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/shuffled-priority-queue/-/shuffled-priority-queue-2.1.0.tgz",
|
||||
"integrity": "sha512-xhdh7fHyMsr0m/w2kDfRJuBFRS96b9l8ZPNWGaQ+PMvnUnZ/Eh+gJJ9NsHBd7P9k0399WYlCLzsy18EaMfyadA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"unordered-set": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-promise": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/signal-promise/-/signal-promise-1.0.3.tgz",
|
||||
"integrity": "sha512-WBgv0UnIq2C+Aeh0/n+IRpP6967eIx9WpynTUoiW3isPpfe1zu2LJzyfXdo9Tgef8yR/sGjcMvoUXD7EYdiz+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/signed-varint": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/signed-varint/-/signed-varint-2.0.1.tgz",
|
||||
"integrity": "sha512-abgDPg1106vuZZOvw7cFwdCABddfJRz5akcCcchzTbhyhYnsG31y4AlZEgp315T7W3nQq5P4xeOm186ZiPVFzw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"varint": "~5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simdle-native": {
|
||||
"version": "1.3.9",
|
||||
"resolved": "https://registry.npmjs.org/simdle-native/-/simdle-native-1.3.9.tgz",
|
||||
"integrity": "sha512-Isc8sP4OiiIU0mpslD4GHEnR0VQWvR/54WN7YtwEDkNdTJVWtpmvsSvsgRlw5BNGxdYXlVRegdnrSu10H/PhvA==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.0",
|
||||
"require-addon": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simdle-universal": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/simdle-universal/-/simdle-universal-1.1.2.tgz",
|
||||
"integrity": "sha512-3n3w1bs+uwgHKQjt6arez83EywNlhZzYvNOhvAASTl/8KqNIcqr6aHyGt3JRlfuUC7iB0tomJRPlJ2cRGIpBzA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"simdle-native": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sodium-native": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-5.1.0.tgz",
|
||||
"integrity": "sha512-3RxgyWyJlhTsABPnJVpCI5CoTDANZTqqFrEPqr+kjfnRaBihpVtMUE3yTF40ukdoB1APXeoBNKF3MzZAIHg39g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bare-assert": "^1.2.0",
|
||||
"require-addon": "^1.1.0",
|
||||
"which-runtime": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"bare": ">=1.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sodium-secretstream": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/sodium-secretstream/-/sodium-secretstream-1.2.0.tgz",
|
||||
"integrity": "sha512-q/DbraNFXm1KfCiiZvapmz5UC3OlpirYFIvBK2MhGaOFSb3gRyk8OXTi17UI9SGfshQNCpsVvlopogbzZNyW6Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.1.1",
|
||||
"sodium-universal": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sodium-universal": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-5.0.1.tgz",
|
||||
"integrity": "sha512-rv+aH+tnKB5H0MAc2UadHShLMslpJsc4wjdnHRtiSIEYpOetCgu8MS4ExQRia+GL/MK3uuCyZPeEsi+J3h+Q+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sodium-native": "^5.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"sodium-javascript": "~0.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"sodium-javascript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/streamx": {
|
||||
"version": "2.25.0",
|
||||
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz",
|
||||
"integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"events-universal": "^1.0.0",
|
||||
"fast-fifo": "^1.3.2",
|
||||
"text-decoder": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/teex": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
|
||||
"integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"streamx": "^2.12.5"
|
||||
}
|
||||
},
|
||||
"node_modules/text-decoder": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
|
||||
"integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.4"
|
||||
}
|
||||
},
|
||||
"node_modules/time-ordered-set": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/time-ordered-set/-/time-ordered-set-2.0.1.tgz",
|
||||
"integrity": "sha512-VJEKmgSN2UiOLB8BpN8Sh2b9LGMHTP5OPrQRpnKjvOheOyzk0mufbjzjKTIG2gO4A+Y+vDJ+0TcLbpUmMLsg8A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/timeout-refresh": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-2.0.1.tgz",
|
||||
"integrity": "sha512-SVqEcMZBsZF9mA78rjzCrYrUs37LMJk3ShZ851ygZYW1cMeIjs9mL57KO6Iv5mmjSQnOe/29/VAfGXo+oRCiVw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/udx-native": {
|
||||
"version": "1.19.2",
|
||||
"resolved": "https://registry.npmjs.org/udx-native/-/udx-native-1.19.2.tgz",
|
||||
"integrity": "sha512-RNYh+UhfryCsF5hE2ZOuIqcZ+qdipXK3UsarwxWJwsUQZFE3ybwz0mPjwb5ev1PMBcjFahWiepS/q0wwL51c2g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.5.0",
|
||||
"bare-events": "^2.2.0",
|
||||
"require-addon": "^1.1.0",
|
||||
"streamx": "^2.22.0"
|
||||
},
|
||||
"engines": {
|
||||
"bare": ">=1.17.4"
|
||||
}
|
||||
},
|
||||
"node_modules/unordered-set": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz",
|
||||
"integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unslab": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/unslab/-/unslab-1.3.0.tgz",
|
||||
"integrity": "sha512-YATkfKAFj47kTzmiQrWXMyRvaVrHsW6MEALa4bm+FhiA2YG4oira+Z3DXN6LrYOYn2Y8eO94Lwl9DOHjs1FpoQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.6"
|
||||
}
|
||||
},
|
||||
"node_modules/varint": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz",
|
||||
"integrity": "sha512-gC13b/bWrqQoKY2EmROCZ+AR0jitc6DnDGaQ6Ls9QpKmuSgJB1eQ7H3KETtQm7qSdMWMKCmsshyCmUwMLh3OAA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/which-runtime": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/which-runtime/-/which-runtime-1.3.2.tgz",
|
||||
"integrity": "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/xache": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/xache/-/xache-1.2.1.tgz",
|
||||
"integrity": "sha512-igRS6jPreJ54ABdzhh4mCDXcz+XMaWO2q1ABRV2yWYuk29jlp8VT7UBdCqNkX7rpYBbXsebVVKkwIuYZjyZNqA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/z32": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/z32/-/z32-1.1.0.tgz",
|
||||
"integrity": "sha512-1WUHy+VS6d0HPNspDxvLssBbeQjXMjSnpv0vH82vRAUfg847NmX3OXozp/hRP5jPhxBbrVzrgvAt+UsGNzRFQQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.5.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-160
@@ -1,160 +0,0 @@
|
||||
# @hyperswarm/secret-stream
|
||||
|
||||
### [See the full API docs at docs.holepunch.to](https://docs.holepunch.to/building-blocks/hyperswarm#secretstream)
|
||||
|
||||
Secret stream backed by Noise and libsodium's secretstream
|
||||
|
||||
```
|
||||
npm install @hyperswarm/secret-stream
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
You can either make a secret stream from an existing transport stream.
|
||||
|
||||
```js
|
||||
const SecretStream = require('@hyperswarm/secret-stream')
|
||||
|
||||
const a = new SecretStream(true, tcpClientStream)
|
||||
const b = new SecretStream(false, tcpServerStream)
|
||||
|
||||
// pipe the underlying rawstreams together
|
||||
|
||||
a.write(Buffer.from('hello encrypted!'))
|
||||
|
||||
b.on('data', function (data) {
|
||||
console.log(data) // <Buffer hello encrypted!>
|
||||
})
|
||||
```
|
||||
|
||||
Or by making your own pipeline
|
||||
|
||||
```js
|
||||
const a = new SecretStream(true)
|
||||
const b = new SecretStream(false)
|
||||
|
||||
// pipe the underlying rawstreams together
|
||||
a.rawStream.pipe(b.rawStream).pipe(a.rawStream)
|
||||
|
||||
a.write(Buffer.from('hello encrypted!'))
|
||||
|
||||
b.on('data', function (data) {
|
||||
console.log(data) // <Buffer hello encrypted!>
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const s = new SecretStream(isInitiator, [rawStream], [options])`
|
||||
|
||||
Make a new stream. `isInitiator` is a boolean indication whether you are the client or the server.
|
||||
`rawStream` can be set to an underlying transport stream you want to run the noise stream over.
|
||||
|
||||
Options include:
|
||||
|
||||
```js
|
||||
{
|
||||
pattern: 'XX', // which noise pattern to use
|
||||
remotePublicKey, // set if your handshake requires it
|
||||
keyPair: { publicKey, secretKey },
|
||||
handshake: { // if you want to use an handshake performed elsewhere pass it here
|
||||
tx,
|
||||
rx,
|
||||
hash,
|
||||
publicKey,
|
||||
remotePublicKey
|
||||
},
|
||||
enableSend: true // (advanced) set false to disable the send API
|
||||
}
|
||||
```
|
||||
|
||||
The SecretStream returned is a Duplex stream that you use as as normal stream, to write/read data from,
|
||||
except it's payloads are encrypted using the libsodium secretstream.
|
||||
|
||||
Note that this uses ed25519 for the handshakes per default.
|
||||
|
||||
If need to load the key pair asynchronously, then secret-stream also supports passing in a promise
|
||||
instead of the keypair that later resolves to `{ publicKey, secretKey }`. The stream lifecycle will wait
|
||||
for the resolution and auto destroy the stream if the promise errors.
|
||||
|
||||
#### `s.start(rawStream, [options])`
|
||||
|
||||
Start a SecretStream from a rawStream asynchrously.
|
||||
|
||||
```js
|
||||
const s = new SecretStream({
|
||||
autoStart: false // call start manually
|
||||
})
|
||||
|
||||
// ... do async stuff or destroy the stream
|
||||
|
||||
s.start(rawStream, {
|
||||
... options from above
|
||||
})
|
||||
```
|
||||
|
||||
#### `s.setTimeout(ms)`
|
||||
|
||||
Set the stream timeout. If no data is received within a `ms` window,
|
||||
the stream is auto destroyed.
|
||||
|
||||
#### `s.setKeepAlive(ms)`
|
||||
|
||||
Send a heartbeat (empty message) every time the socket is idle for `ms` milliseconds. **Note:** If one side calls `s.setKeepAlive()` and the other does not, then the empty messages will be passed through to the piped stream.
|
||||
|
||||
#### `s.publicKey`
|
||||
|
||||
Get the local public key.
|
||||
|
||||
#### `s.remotePublicKey`
|
||||
|
||||
Get the remote's public key.
|
||||
Populated after `open` is emitted.
|
||||
|
||||
#### `s.handshakeHash`
|
||||
|
||||
Get the unique hash of this handshake.
|
||||
Populated after `open` is emitted.
|
||||
|
||||
#### `s.keepAlive`
|
||||
|
||||
Get the interval (in milliseconds) at which keep-alive messages are sent (0 means none are sent).
|
||||
|
||||
#### `s.sendKeepAlive()`
|
||||
|
||||
A convenience method that sends an empty message.
|
||||
|
||||
#### `s.rawBytesWritten`
|
||||
|
||||
The number of bytes (measured after encryption) written.
|
||||
|
||||
#### `s.rawBytesRead`
|
||||
|
||||
The number of bytes (measured before decryption) received.
|
||||
|
||||
#### `s.on('connect', onconnect)`
|
||||
|
||||
Emitted when the handshake is fully done.
|
||||
It is safe to write to the stream immediately though, as data is buffered
|
||||
internally before the handshake has been completed.
|
||||
|
||||
#### `await s.send(buffer)`
|
||||
|
||||
Sends an encrypted unordered message, see [udx-native](https://github.com/holepunchto/udx-native/tree/main?tab=readme-ov-file#await-streamsendbuffer) for details.
|
||||
This method with silently fail if called before handshake is complete or if the underlying rawStream is not an UDX-stream (not capable of UDP).
|
||||
|
||||
#### `s.trySend(buffer)`
|
||||
|
||||
Same as `send(buffer)` but does not return a promise.
|
||||
|
||||
#### `s.on('message', onmessage)`
|
||||
|
||||
Emmitted when an unordered message is received
|
||||
|
||||
#### `keyPair = SecretStream.keyPair([seed])`
|
||||
|
||||
Generate a ed25519 key pair.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
-645
@@ -1,645 +0,0 @@
|
||||
const { Pull, Push, HEADERBYTES, KEYBYTES, ABYTES } = require('sodium-secretstream')
|
||||
const sodium = require('sodium-universal')
|
||||
const crypto = require('hypercore-crypto')
|
||||
const { Duplex, Writable, getStreamError } = require('streamx')
|
||||
const b4a = require('b4a')
|
||||
const Timeout = require('timeout-refresh')
|
||||
const unslab = require('unslab')
|
||||
const Bridge = require('./lib/bridge')
|
||||
const Handshake = require('./lib/handshake')
|
||||
|
||||
const IDHEADERBYTES = HEADERBYTES + 32
|
||||
const [NS_INITIATOR, NS_RESPONDER, NS_SEND] = crypto.namespace('hyperswarm/secret-stream', 3)
|
||||
const MAX_ATOMIC_WRITE = 256 * 256 * 256 - 1
|
||||
|
||||
module.exports = class NoiseSecretStream extends Duplex {
|
||||
constructor(isInitiator, rawStream, opts = {}) {
|
||||
super({ mapWritable: toBuffer })
|
||||
|
||||
if (typeof isInitiator !== 'boolean') {
|
||||
throw new Error('isInitiator should be a boolean')
|
||||
}
|
||||
|
||||
this.noiseStream = this
|
||||
this.isInitiator = isInitiator
|
||||
this.rawStream = null
|
||||
|
||||
this.publicKey = opts.publicKey || null
|
||||
this.remotePublicKey = opts.remotePublicKey || null
|
||||
this.handshakeHash = null
|
||||
this.connected = false
|
||||
this.keepAlive = opts.keepAlive || 0
|
||||
this.timeout = 0
|
||||
this.enableSend = opts.enableSend !== false
|
||||
|
||||
// pointer for upstream to set data here if they want
|
||||
this.userData = null
|
||||
|
||||
let openedDone = null
|
||||
this.opened = new Promise((resolve) => {
|
||||
openedDone = resolve
|
||||
})
|
||||
|
||||
this.rawBytesWritten = 0
|
||||
this.rawBytesRead = 0
|
||||
|
||||
// metadata used by 'hyperdht'
|
||||
this.relay = null
|
||||
this.puncher = null
|
||||
|
||||
// unwrapped raw stream
|
||||
this._rawStream = null
|
||||
|
||||
// handshake state
|
||||
this._handshake = null
|
||||
this._handshakePattern = opts.pattern || null
|
||||
this._handshakeDone = null
|
||||
|
||||
// message parsing state
|
||||
this._state = 0
|
||||
this._len = 0
|
||||
this._tmp = 1
|
||||
this._message = null
|
||||
|
||||
this._openedDone = openedDone
|
||||
this._startDone = null
|
||||
this._drainDone = null
|
||||
this._outgoingPlain = null
|
||||
this._outgoingWrapped = null
|
||||
this._utp = null
|
||||
this._setup = true
|
||||
this._ended = 2
|
||||
this._encrypt = null
|
||||
this._decrypt = null
|
||||
this._timeoutTimer = null
|
||||
this._keepAliveTimer = null
|
||||
this._sendState = null
|
||||
|
||||
if (opts.autoStart !== false) this.start(rawStream, opts)
|
||||
|
||||
// wiggle it to trigger open immediately (TODO add streamx option for this)
|
||||
this.resume()
|
||||
this.pause()
|
||||
}
|
||||
|
||||
static keyPair(seed) {
|
||||
return Handshake.keyPair(seed)
|
||||
}
|
||||
|
||||
static id(handshakeHash, isInitiator, id) {
|
||||
return streamId(handshakeHash, isInitiator, id)
|
||||
}
|
||||
|
||||
setTimeout(ms) {
|
||||
if (!ms) ms = 0
|
||||
|
||||
this._clearTimeout()
|
||||
this.timeout = ms
|
||||
|
||||
if (!ms || this.rawStream === null) return
|
||||
|
||||
this._timeoutTimer = Timeout.once(ms, destroyTimeout, this)
|
||||
this._timeoutTimer.unref()
|
||||
}
|
||||
|
||||
setKeepAlive(ms) {
|
||||
if (!ms) ms = 0
|
||||
|
||||
this._clearKeepAlive()
|
||||
|
||||
this.keepAlive = ms
|
||||
|
||||
if (!ms || this.rawStream === null) return
|
||||
|
||||
this._keepAliveTimer = Timeout.on(ms, sendKeepAlive, this)
|
||||
this._keepAliveTimer.unref()
|
||||
}
|
||||
|
||||
sendKeepAlive() {
|
||||
const empty = this.alloc(0)
|
||||
this.write(empty)
|
||||
}
|
||||
|
||||
start(rawStream, opts = {}) {
|
||||
if (rawStream) {
|
||||
this.rawStream = rawStream
|
||||
this._rawStream = rawStream
|
||||
if (typeof this.rawStream.setContentSize === 'function') {
|
||||
this._utp = rawStream
|
||||
}
|
||||
} else {
|
||||
this.rawStream = new Bridge(this)
|
||||
this._rawStream = this.rawStream.reverse
|
||||
}
|
||||
|
||||
this.rawStream.on('error', this._onrawerror.bind(this))
|
||||
this.rawStream.on('close', this._onrawclose.bind(this))
|
||||
|
||||
this._startHandshake(opts.handshake, opts.keyPair || null)
|
||||
this._continueOpen(null)
|
||||
|
||||
if (this.destroying) return
|
||||
|
||||
if (opts.data) this._onrawdata(opts.data)
|
||||
if (opts.ended) this._onrawend()
|
||||
|
||||
if (this.keepAlive > 0 && this._keepAliveTimer === null) {
|
||||
this.setKeepAlive(this.keepAlive)
|
||||
}
|
||||
|
||||
if (this.timeout > 0 && this._timeoutTimer === null) {
|
||||
this.setTimeout(this.timeout)
|
||||
}
|
||||
}
|
||||
|
||||
async flush() {
|
||||
if ((await this.opened) === false) return false
|
||||
if ((await Writable.drained(this)) === false) return false
|
||||
if (this.destroying) return false
|
||||
|
||||
if (this.rawStream !== null && this.rawStream.flush) {
|
||||
return await this.rawStream.flush()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
_continueOpen(err) {
|
||||
if (err) this.destroy(err)
|
||||
if (this._startDone === null) return
|
||||
const done = this._startDone
|
||||
this._startDone = null
|
||||
this._open(done)
|
||||
}
|
||||
|
||||
_onkeypairpromise(p) {
|
||||
const self = this
|
||||
const cont = this._continueOpen.bind(this)
|
||||
|
||||
p.then(onkeypair, cont)
|
||||
|
||||
function onkeypair(kp) {
|
||||
self._onkeypair(kp)
|
||||
cont(null)
|
||||
}
|
||||
}
|
||||
|
||||
_onkeypair(keyPair) {
|
||||
const pattern = this._handshakePattern || 'XX'
|
||||
const remotePublicKey = this.remotePublicKey
|
||||
|
||||
this._handshake = new Handshake(this.isInitiator, keyPair, remotePublicKey, pattern)
|
||||
this.publicKey = this._handshake.keyPair.publicKey
|
||||
}
|
||||
|
||||
_startHandshake(handshake, keyPair) {
|
||||
if (handshake) {
|
||||
const { tx, rx, hash, publicKey, remotePublicKey } = handshake
|
||||
this._setupSecretStream(tx, rx, hash, publicKey, remotePublicKey)
|
||||
return
|
||||
}
|
||||
|
||||
if (!keyPair) keyPair = Handshake.keyPair()
|
||||
|
||||
if (typeof keyPair.then === 'function') {
|
||||
this._onkeypairpromise(keyPair)
|
||||
} else {
|
||||
this._onkeypair(keyPair)
|
||||
}
|
||||
}
|
||||
|
||||
_onrawerror(err) {
|
||||
this.destroy(err)
|
||||
}
|
||||
|
||||
_onrawclose() {
|
||||
if (this._ended !== 0) this.destroy()
|
||||
}
|
||||
|
||||
_onrawdata(data) {
|
||||
let offset = 0
|
||||
|
||||
if (this._timeoutTimer !== null) {
|
||||
this._timeoutTimer.refresh()
|
||||
}
|
||||
|
||||
do {
|
||||
switch (this._state) {
|
||||
case 0: {
|
||||
while (this._tmp !== 0x1000000 && offset < data.byteLength) {
|
||||
const v = data[offset++]
|
||||
this._len += this._tmp * v
|
||||
this._tmp *= 256
|
||||
}
|
||||
|
||||
if (this._tmp === 0x1000000) {
|
||||
this._tmp = 0
|
||||
this._state = 1
|
||||
const unprocessed = data.byteLength - offset
|
||||
if (unprocessed < this._len && this._utp !== null)
|
||||
this._utp.setContentSize(this._len - unprocessed)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 1: {
|
||||
const missing = this._len - this._tmp
|
||||
const end = missing + offset
|
||||
|
||||
if (this._message === null && end <= data.byteLength) {
|
||||
this._message = data.subarray(offset, end)
|
||||
offset += missing
|
||||
this._incoming()
|
||||
break
|
||||
}
|
||||
|
||||
const unprocessed = data.byteLength - offset
|
||||
|
||||
if (this._message === null) {
|
||||
this._message = b4a.allocUnsafe(this._len)
|
||||
}
|
||||
|
||||
b4a.copy(data, this._message, this._tmp, offset)
|
||||
this._tmp += unprocessed
|
||||
|
||||
if (end <= data.byteLength) {
|
||||
offset += missing
|
||||
this._incoming()
|
||||
} else {
|
||||
offset += unprocessed
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
} while (offset < data.byteLength && !this.destroying)
|
||||
}
|
||||
|
||||
_onrawend() {
|
||||
this._ended--
|
||||
this.push(null)
|
||||
}
|
||||
|
||||
_onrawdrain() {
|
||||
const drain = this._drainDone
|
||||
if (drain === null) return
|
||||
this._drainDone = null
|
||||
drain()
|
||||
}
|
||||
|
||||
_read(cb) {
|
||||
this.rawStream.resume()
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_incoming() {
|
||||
const message = this._message
|
||||
|
||||
this._state = 0
|
||||
this._len = 0
|
||||
this._tmp = 1
|
||||
this._message = null
|
||||
|
||||
if (this._setup === true) {
|
||||
if (this._handshake) {
|
||||
this._onhandshakert(this._handshake.recv(message))
|
||||
} else {
|
||||
if (message.byteLength !== IDHEADERBYTES) {
|
||||
this.destroy(new Error('Invalid header message received'))
|
||||
return
|
||||
}
|
||||
|
||||
const remoteId = message.subarray(0, 32)
|
||||
const expectedId = streamId(this.handshakeHash, !this.isInitiator)
|
||||
const header = message.subarray(32)
|
||||
|
||||
if (!b4a.equals(expectedId, remoteId)) {
|
||||
this.destroy(new Error('Invalid header received'))
|
||||
return
|
||||
}
|
||||
|
||||
this._decrypt.init(header)
|
||||
this._setup = false // setup is now done
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (message.byteLength < ABYTES) {
|
||||
this.destroy(new Error('Invalid message received'))
|
||||
return
|
||||
}
|
||||
|
||||
this.rawBytesRead += message.byteLength
|
||||
|
||||
const plain = message.subarray(1, message.byteLength - ABYTES + 1)
|
||||
|
||||
try {
|
||||
this._decrypt.next(message, plain)
|
||||
} catch (err) {
|
||||
this.destroy(err)
|
||||
return
|
||||
}
|
||||
|
||||
// If keep alive is selective, eat the empty buffers (ie assume the other side has it enabled also)
|
||||
if (plain.byteLength === 0 && this.keepAlive !== 0) return
|
||||
|
||||
if (this.push(plain) === false) {
|
||||
this.rawStream.pause()
|
||||
}
|
||||
}
|
||||
|
||||
_onhandshakert(h) {
|
||||
if (this._handshakeDone === null) return
|
||||
|
||||
if (h !== null) {
|
||||
if (h.data) this._rawStream.write(h.data)
|
||||
if (!h.tx) return
|
||||
}
|
||||
|
||||
const done = this._handshakeDone
|
||||
const publicKey = this._handshake.keyPair.publicKey
|
||||
|
||||
this._handshakeDone = null
|
||||
this._handshake = null
|
||||
|
||||
if (h === null) return done(new Error('Noise handshake failed'))
|
||||
|
||||
this._setupSecretStream(h.tx, h.rx, h.hash, publicKey, h.remotePublicKey)
|
||||
this._resolveOpened(true)
|
||||
done(null)
|
||||
}
|
||||
|
||||
_setupSecretStream(tx, rx, handshakeHash, publicKey, remotePublicKey) {
|
||||
const buf = b4a.allocUnsafeSlow(3 + IDHEADERBYTES)
|
||||
writeUint24le(IDHEADERBYTES, buf)
|
||||
|
||||
this._encrypt = new Push(unslab(tx.subarray(0, KEYBYTES)), undefined, buf.subarray(3 + 32))
|
||||
this._decrypt = new Pull(unslab(rx.subarray(0, KEYBYTES)))
|
||||
|
||||
this.publicKey = publicKey
|
||||
this.remotePublicKey = remotePublicKey
|
||||
this.handshakeHash = handshakeHash
|
||||
|
||||
const id = buf.subarray(3, 3 + 32)
|
||||
streamId(handshakeHash, this.isInitiator, id)
|
||||
|
||||
// initialize secretbox state for unordered messages
|
||||
this._setupSecretSend(handshakeHash)
|
||||
|
||||
this.emit('handshake')
|
||||
// if rawStream is a bridge, also emit it there
|
||||
if (this.rawStream !== this._rawStream) this.rawStream.emit('handshake')
|
||||
|
||||
if (this.destroying) return
|
||||
|
||||
this._rawStream.write(buf)
|
||||
}
|
||||
|
||||
_setupSecretSend(handshakeHash) {
|
||||
this._sendState = b4a.allocUnsafeSlow(32 + 32 + 8 + 8)
|
||||
const encrypt = this._sendState.subarray(0, 32) // secrets
|
||||
const decrypt = this._sendState.subarray(32, 64)
|
||||
const counter = this._sendState.subarray(64, 72) // nonce
|
||||
const initial = this._sendState.subarray(72)
|
||||
|
||||
const inputs = this.isInitiator
|
||||
? [
|
||||
[NS_INITIATOR, NS_SEND],
|
||||
[NS_RESPONDER, NS_SEND]
|
||||
]
|
||||
: [
|
||||
[NS_RESPONDER, NS_SEND],
|
||||
[NS_INITIATOR, NS_SEND]
|
||||
]
|
||||
|
||||
sodium.crypto_generichash_batch(encrypt, inputs[0], handshakeHash)
|
||||
sodium.crypto_generichash_batch(decrypt, inputs[1], handshakeHash)
|
||||
|
||||
sodium.randombytes_buf(initial)
|
||||
counter.set(initial)
|
||||
}
|
||||
|
||||
_open(cb) {
|
||||
// no autostart or no handshake yet
|
||||
if (this._rawStream === null || (this._handshake === null && this._encrypt === null)) {
|
||||
this._startDone = cb
|
||||
return
|
||||
}
|
||||
|
||||
this._rawStream.on('data', this._onrawdata.bind(this))
|
||||
this._rawStream.on('end', this._onrawend.bind(this))
|
||||
this._rawStream.on('drain', this._onrawdrain.bind(this))
|
||||
|
||||
if (this.enableSend) this._rawStream.on('message', this._onmessage.bind(this))
|
||||
|
||||
if (this._encrypt !== null) {
|
||||
this._resolveOpened(true)
|
||||
return cb(null)
|
||||
}
|
||||
|
||||
this._handshakeDone = cb
|
||||
|
||||
if (this.isInitiator) this._onhandshakert(this._handshake.send())
|
||||
}
|
||||
|
||||
_predestroy() {
|
||||
if (this.rawStream) {
|
||||
const error = getStreamError(this)
|
||||
this.rawStream.destroy(error)
|
||||
}
|
||||
|
||||
if (this._startDone !== null) {
|
||||
const done = this._startDone
|
||||
this._startDone = null
|
||||
done(new Error('Stream destroyed'))
|
||||
}
|
||||
|
||||
if (this._handshakeDone !== null) {
|
||||
const done = this._handshakeDone
|
||||
this._handshakeDone = null
|
||||
done(new Error('Stream destroyed'))
|
||||
}
|
||||
|
||||
if (this._drainDone !== null) {
|
||||
const done = this._drainDone
|
||||
this._drainDone = null
|
||||
done(new Error('Stream destroyed'))
|
||||
}
|
||||
}
|
||||
|
||||
_write(data, cb) {
|
||||
let wrapped = this._outgoingWrapped
|
||||
|
||||
if (data !== this._outgoingPlain) {
|
||||
wrapped = b4a.allocUnsafe(data.byteLength + 3 + ABYTES)
|
||||
wrapped.set(data, 4)
|
||||
} else {
|
||||
this._outgoingWrapped = this._outgoingPlain = null
|
||||
}
|
||||
|
||||
if (wrapped.byteLength - 3 > MAX_ATOMIC_WRITE) {
|
||||
return cb(
|
||||
new Error(
|
||||
'Message is too large for an atomic write. Max size is ' + MAX_ATOMIC_WRITE + ' bytes.'
|
||||
)
|
||||
)
|
||||
}
|
||||
this.rawBytesWritten += wrapped.byteLength
|
||||
|
||||
writeUint24le(wrapped.byteLength - 3, wrapped)
|
||||
// offset 4 so we can do it in-place
|
||||
this._encrypt.next(wrapped.subarray(4, 4 + data.byteLength), wrapped.subarray(3))
|
||||
|
||||
if (this._keepAliveTimer !== null) this._keepAliveTimer.refresh()
|
||||
|
||||
if (this._rawStream.write(wrapped) === false) {
|
||||
this._drainDone = cb
|
||||
} else {
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
_final(cb) {
|
||||
this._clearKeepAlive()
|
||||
this._ended--
|
||||
this._rawStream.end()
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_resolveOpened(val) {
|
||||
if (this._openedDone === null) return
|
||||
const opened = this._openedDone
|
||||
this._openedDone = null
|
||||
opened(val)
|
||||
if (!val) return
|
||||
this.connected = true
|
||||
this.emit('connect')
|
||||
}
|
||||
|
||||
_clearTimeout() {
|
||||
if (this._timeoutTimer === null) return
|
||||
this._timeoutTimer.destroy()
|
||||
this._timeoutTimer = null
|
||||
this.timeout = 0
|
||||
}
|
||||
|
||||
_clearKeepAlive() {
|
||||
if (this._keepAliveTimer === null) return
|
||||
this._keepAliveTimer.destroy()
|
||||
this._keepAliveTimer = null
|
||||
this.keepAlive = 0
|
||||
}
|
||||
|
||||
_destroy(cb) {
|
||||
this._clearKeepAlive()
|
||||
this._clearTimeout()
|
||||
this._resolveOpened(false)
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_boxMessage(buffer) {
|
||||
const MB = sodium.crypto_secretbox_MACBYTES // 16
|
||||
const NB = sodium.crypto_secretbox_NONCEBYTES // 24
|
||||
|
||||
const counter = this._sendState.subarray(64, 72)
|
||||
sodium.sodium_increment(counter)
|
||||
if (b4a.equals(counter, this._sendState.subarray(72))) {
|
||||
this.destroy(new Error('udp send nonce exchausted'))
|
||||
return
|
||||
}
|
||||
|
||||
const secret = this._sendState.subarray(0, 32)
|
||||
const envelope = b4a.allocUnsafe(8 + MB + buffer.byteLength)
|
||||
const nonce = envelope.subarray(0, NB)
|
||||
const ciphertext = envelope.subarray(8)
|
||||
|
||||
b4a.fill(nonce, 0) // pad suffix
|
||||
nonce.set(counter)
|
||||
|
||||
sodium.crypto_secretbox_easy(ciphertext, buffer, nonce, secret)
|
||||
return envelope
|
||||
}
|
||||
|
||||
send(buffer) {
|
||||
if (!this._sendState) return
|
||||
if (!this.rawStream?.send) return // udx-stream expected
|
||||
|
||||
const message = this._boxMessage(buffer)
|
||||
return this.rawStream.send(message)
|
||||
}
|
||||
|
||||
trySend(buffer) {
|
||||
if (!this._sendState) return
|
||||
if (!this.rawStream?.trySend) return // udx-stream expected
|
||||
|
||||
const message = this._boxMessage(buffer)
|
||||
this.rawStream.trySend(message)
|
||||
}
|
||||
|
||||
_onmessage(buffer) {
|
||||
if (!this._sendState) return // messages before handshake are dropped
|
||||
|
||||
const MB = sodium.crypto_secretbox_MACBYTES // 16
|
||||
const NB = sodium.crypto_secretbox_NONCEBYTES // 24
|
||||
|
||||
if (buffer.byteLength < NB) return // Invalid message
|
||||
|
||||
const nonce = b4a.allocUnsafe(NB)
|
||||
b4a.fill(nonce, 0)
|
||||
nonce.set(buffer.subarray(0, 8))
|
||||
|
||||
const secret = this._sendState.subarray(32, 64)
|
||||
const ciphertext = buffer.subarray(8)
|
||||
const plain = buffer.subarray(8, buffer.byteLength - MB)
|
||||
|
||||
if (ciphertext.byteLength < MB) return // invalid message
|
||||
|
||||
const success = sodium.crypto_secretbox_open_easy(plain, ciphertext, nonce, secret)
|
||||
|
||||
if (success) this.emit('message', plain)
|
||||
}
|
||||
|
||||
alloc(len) {
|
||||
const buf = b4a.allocUnsafe(len + 3 + ABYTES)
|
||||
this._outgoingWrapped = buf
|
||||
this._outgoingPlain = buf.subarray(4, buf.byteLength - ABYTES + 1)
|
||||
return this._outgoingPlain
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
isInitiator: this.isInitiator,
|
||||
publicKey: this.publicKey && b4a.toString(this.publicKey, 'hex'),
|
||||
remotePublicKey: this.remotePublicKey && b4a.toString(this.remotePublicKey, 'hex'),
|
||||
connected: this.connected,
|
||||
destroying: this.destroying,
|
||||
destroyed: this.destroyed,
|
||||
rawStream: this.rawStream && this.rawStream.toJSON ? this.rawStream.toJSON() : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeUint24le(n, buf) {
|
||||
buf[0] = n & 255
|
||||
buf[1] = (n >>> 8) & 255
|
||||
buf[2] = (n >>> 16) & 255
|
||||
}
|
||||
|
||||
function streamId(handshakeHash, isInitiator, out = b4a.allocUnsafe(32)) {
|
||||
sodium.crypto_generichash(out, isInitiator ? NS_INITIATOR : NS_RESPONDER, handshakeHash)
|
||||
return out
|
||||
}
|
||||
|
||||
function toBuffer(data) {
|
||||
return typeof data === 'string' ? b4a.from(data) : data
|
||||
}
|
||||
|
||||
function destroyTimeout() {
|
||||
this.destroy(new Error('Stream timed out'))
|
||||
}
|
||||
|
||||
function sendKeepAlive() {
|
||||
const empty = this.alloc(0)
|
||||
this.write(empty)
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
const { Duplex, Writable } = require('streamx')
|
||||
|
||||
class ReversePassThrough extends Duplex {
|
||||
constructor(s) {
|
||||
super()
|
||||
this._stream = s
|
||||
this._ondrain = null
|
||||
}
|
||||
|
||||
_write(data, cb) {
|
||||
if (this._stream.push(data) === false) {
|
||||
this._stream._ondrain = cb
|
||||
} else {
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
_final(cb) {
|
||||
this._stream.push(null)
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_read(cb) {
|
||||
const ondrain = this._ondrain
|
||||
this._ondrain = null
|
||||
if (ondrain) ondrain()
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = class Bridge extends Duplex {
|
||||
constructor(noiseStream) {
|
||||
super()
|
||||
|
||||
this.noiseStream = noiseStream
|
||||
|
||||
this._ondrain = null
|
||||
this.reverse = new ReversePassThrough(this)
|
||||
}
|
||||
|
||||
get publicKey() {
|
||||
return this.noiseStream.publicKey
|
||||
}
|
||||
|
||||
get remotePublicKey() {
|
||||
return this.noiseStream.remotePublicKey
|
||||
}
|
||||
|
||||
get handshakeHash() {
|
||||
return this.noiseStream.handshakeHash
|
||||
}
|
||||
|
||||
flush() {
|
||||
return Writable.drained(this)
|
||||
}
|
||||
|
||||
_read(cb) {
|
||||
const ondrain = this._ondrain
|
||||
this._ondrain = null
|
||||
if (ondrain) ondrain()
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_write(data, cb) {
|
||||
if (this.reverse.push(data) === false) {
|
||||
this.reverse._ondrain = cb
|
||||
} else {
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
|
||||
_final(cb) {
|
||||
this.reverse.push(null)
|
||||
cb(null)
|
||||
}
|
||||
}
|
||||
Generated
Vendored
-78
@@ -1,78 +0,0 @@
|
||||
const sodium = require('sodium-universal')
|
||||
const curve = require('noise-curve-ed')
|
||||
const Noise = require('noise-handshake')
|
||||
const b4a = require('b4a')
|
||||
|
||||
const EMPTY = b4a.alloc(0)
|
||||
|
||||
module.exports = class Handshake {
|
||||
constructor(isInitiator, keyPair, remotePublicKey, pattern) {
|
||||
this.isInitiator = isInitiator
|
||||
this.keyPair = keyPair
|
||||
this.noise = new Noise(pattern, isInitiator, keyPair, { curve })
|
||||
this.noise.initialise(EMPTY, remotePublicKey)
|
||||
this.destroyed = false
|
||||
}
|
||||
|
||||
static keyPair(seed) {
|
||||
const publicKey = b4a.alloc(32)
|
||||
const secretKey = b4a.alloc(64)
|
||||
if (seed) sodium.crypto_sign_seed_keypair(publicKey, secretKey, seed)
|
||||
else sodium.crypto_sign_keypair(publicKey, secretKey)
|
||||
return { publicKey, secretKey }
|
||||
}
|
||||
|
||||
recv(data) {
|
||||
try {
|
||||
this.noise.recv(data)
|
||||
if (this.noise.complete) return this._return(null)
|
||||
return this.send()
|
||||
} catch {
|
||||
this.destroy()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// note that the data returned here is framed so we don't have to do an extra copy
|
||||
// when sending it...
|
||||
send() {
|
||||
try {
|
||||
const data = this.noise.send()
|
||||
const wrap = b4a.allocUnsafe(data.byteLength + 3)
|
||||
|
||||
writeUint24le(data.byteLength, wrap)
|
||||
wrap.set(data, 3)
|
||||
|
||||
return this._return(wrap)
|
||||
} catch {
|
||||
this.destroy()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.destroyed) return
|
||||
this.destroyed = true
|
||||
}
|
||||
|
||||
_return(data) {
|
||||
const tx = this.noise.complete ? b4a.toBuffer(this.noise.tx) : null
|
||||
const rx = this.noise.complete ? b4a.toBuffer(this.noise.rx) : null
|
||||
const hash = this.noise.complete ? b4a.toBuffer(this.noise.hash) : null
|
||||
const remotePublicKey = this.noise.complete ? b4a.toBuffer(this.noise.rs) : null
|
||||
|
||||
return {
|
||||
data,
|
||||
remotePublicKey,
|
||||
hash,
|
||||
tx,
|
||||
rx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeUint24le(n, buf) {
|
||||
buf[0] = n & 255
|
||||
buf[1] = (n >>> 8) & 255
|
||||
buf[2] = (n >>> 16) & 255
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"name": "@hyperswarm/secret-stream",
|
||||
"version": "6.9.1",
|
||||
"description": "Secret stream backed by Noise and libsodium's secretstream",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib/**.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"b4a": "^1.1.0",
|
||||
"hypercore-crypto": "^3.3.1",
|
||||
"noise-curve-ed": "^2.0.1",
|
||||
"noise-handshake": "^4.0.0",
|
||||
"sodium-secretstream": "^1.1.0",
|
||||
"sodium-universal": "^5.0.0",
|
||||
"streamx": "^2.14.0",
|
||||
"timeout-refresh": "^2.0.0",
|
||||
"unslab": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"brittle": "^3.3.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-config-holepunch": "^2.0.0",
|
||||
"udx-native": "^1.13.2"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check .",
|
||||
"test": "brittle test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/holepunchto/hyperswarm-secret-stream.git"
|
||||
},
|
||||
"author": "Mathias Buus (@mafintosh)",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/hyperswarm-secret-stream/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/hyperswarm-secret-stream"
|
||||
}
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
# adaptive-timeout
|
||||
|
||||
Adaptive timeout calculation with EWMA-based tracking and fallback strategies.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install adaptive-timeout
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const AdaptiveTimeout = require('adaptive-timeout')
|
||||
|
||||
const timeouts = new AdaptiveTimeout()
|
||||
|
||||
// Record a sample when you get a response
|
||||
timeouts.put('10.0.0.1:8080', 150)
|
||||
|
||||
// Get timeout for next request (attempt 1, 2, 3...)
|
||||
timeouts.get('10.0.0.1:8080', 1) // adaptive based on recorded samples
|
||||
timeouts.get('unknown-peer', 1) // uses fallback strategy
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `const timeouts = new AdaptiveTimeout([options])`
|
||||
|
||||
Create a new instance.
|
||||
|
||||
Options:
|
||||
|
||||
- `maxSize` - max cache entries (default: `65536`)
|
||||
- `maxAge` - entry TTL in ms (default: `600000` / 10 minutes)
|
||||
- `fallback` - timeout sequence for unknown keys (default: `[500, 750, 1000, 1500, 2000]`)
|
||||
- `min` - minimum timeout for known keys (default: `300`)
|
||||
- `max` - maximum timeout for known keys (default: `5000`)
|
||||
- `jitter` - random jitter range in ms (default: `256`)
|
||||
|
||||
#### `timeouts.put(key, value)`
|
||||
|
||||
Record a sample. Updates the exponentially weighted moving average.
|
||||
|
||||
Returns `{ avg, variance }`.
|
||||
|
||||
#### `timeouts.get(key, [attempt])`
|
||||
|
||||
Get a timeout value.
|
||||
|
||||
For known keys: calculates adaptive timeout with linear backoff based on attempt number.
|
||||
|
||||
For unknown keys: returns value from fallback sequence based on attempt number.
|
||||
|
||||
#### `timeouts.getValue(key)`
|
||||
|
||||
Get raw stats for a key. Returns `{ avg, variance }` or `null`.
|
||||
|
||||
#### `timeouts.has(key)`
|
||||
|
||||
Check if a key exists.
|
||||
|
||||
#### `timeouts.delete(key)`
|
||||
|
||||
Remove a key.
|
||||
|
||||
#### `timeouts.clear()`
|
||||
|
||||
Remove all entries.
|
||||
|
||||
#### `timeouts.size`
|
||||
|
||||
Number of entries.
|
||||
|
||||
## How it works
|
||||
|
||||
Uses TCP-style EWMA (exponentially weighted moving average) to track values:
|
||||
|
||||
- `avg` blends 87.5% old + 12.5% new sample
|
||||
- `variance` blends 75% old + 25% new deviation
|
||||
|
||||
Timeout for known keys: `(avg + 2 * variance) * attempt + jitter`
|
||||
|
||||
Unknown keys use an aggressive fallback sequence to probe quickly.
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
declare module '@holepunchto/adaptive-timeout' {
|
||||
interface AdaptiveTimeoutOptions {
|
||||
maxSize?: number
|
||||
maxAge?: number
|
||||
fallback?: number[]
|
||||
min?: number
|
||||
max?: number
|
||||
jitter?: number
|
||||
}
|
||||
|
||||
interface Stats {
|
||||
avg: number
|
||||
variance: number
|
||||
}
|
||||
|
||||
declare class AdaptiveTimeout {
|
||||
constructor(opts?: AdaptiveTimeoutOptions)
|
||||
|
||||
getValue(key: string): Stats | null
|
||||
put(key: string, value: number): Stats
|
||||
get(key: string, attempt?: number): number
|
||||
has(key: string): boolean
|
||||
delete(key: string): boolean
|
||||
clear(): void
|
||||
|
||||
// Default - aggressive ramp
|
||||
static TimeoutAggressive: string[]
|
||||
|
||||
// Linear - steady increase
|
||||
static TimeoutLinear: string[]
|
||||
|
||||
// Exponential - slow start, rapid backoff
|
||||
static TimeoutExponential: string[]
|
||||
|
||||
// Gentle - conservative, patient
|
||||
static TimeoutGentle: string[]
|
||||
|
||||
// Fast - rapid fire retries
|
||||
static TimeoutFast: string[]
|
||||
|
||||
// U-shape - long, short, long
|
||||
static TimeoutUShape: string[]
|
||||
|
||||
// Inverse U - short, long, short
|
||||
static TimeoutInverseU: string[]
|
||||
|
||||
// Sawtooth - alternating fast/slow
|
||||
static TimeoutSawtooth: string[]
|
||||
|
||||
// Plateau - quick ramp then steady
|
||||
static TimeoutPlateau: string[]
|
||||
|
||||
// Logarithmic - diminishing increases
|
||||
static TimeoutLogarithmic: string[]
|
||||
}
|
||||
|
||||
export = AdaptiveTimeout
|
||||
}
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
const Cache = require('xache')
|
||||
|
||||
module.exports = class AdaptiveTimeout {
|
||||
constructor(opts = {}) {
|
||||
this._cache = new Cache({
|
||||
maxSize: opts.maxSize || 65536,
|
||||
maxAge: opts.maxAge || 10 * 60 * 1000 // 10 minutes
|
||||
})
|
||||
this._fallback = opts.fallback || AdaptiveTimeout.TimeoutExponential
|
||||
this._min = opts.min ?? 300
|
||||
this._max = opts.max || 4000
|
||||
this._jitter = opts.jitter ?? 256
|
||||
}
|
||||
|
||||
// Default - aggressive ramp
|
||||
static TimeoutAggressive = [500, 750, 1000, 1500, 2000]
|
||||
|
||||
// Linear - steady increase
|
||||
static TimeoutLinear = [500, 1000, 1500, 2000, 2500]
|
||||
|
||||
// Exponential - slow start, rapid backoff
|
||||
static TimeoutExponential = [250, 500, 1000, 2000, 4000]
|
||||
|
||||
// Gentle - conservative, patient
|
||||
static TimeoutGentle = [1000, 1250, 1500, 1750, 2000]
|
||||
|
||||
// Fast - rapid fire retries
|
||||
static TimeoutFast = [200, 400, 600, 800, 1000]
|
||||
|
||||
// U-shape - long, short, long
|
||||
static TimeoutUShape = [1500, 750, 500, 750, 1500]
|
||||
|
||||
// Inverse U - short, long, short
|
||||
static TimeoutInverseU = [500, 1000, 1500, 1000, 500]
|
||||
|
||||
// Sawtooth - alternating fast/slow
|
||||
static TimeoutSawtooth = [500, 1500, 500, 1500, 500]
|
||||
|
||||
// Plateau - quick ramp then steady
|
||||
static TimeoutPlateau = [500, 1000, 2000, 2000, 2000]
|
||||
|
||||
// Logarithmic - diminishing increases
|
||||
static TimeoutLogarithmic = [500, 1000, 1300, 1500, 1600]
|
||||
|
||||
getValue(key) {
|
||||
return this._cache.get(key)
|
||||
}
|
||||
|
||||
put(key, value) {
|
||||
let p = this._cache.get(key)
|
||||
|
||||
if (!p) {
|
||||
p = { avg: value, variance: value >> 1 }
|
||||
} else {
|
||||
// blend 75% old + 25% new deviation
|
||||
p.variance += (Math.abs(p.avg - value) - p.variance) >> 2
|
||||
// blend 87.5% old + 12.5% new sample
|
||||
p.avg += (value - p.avg) >> 3
|
||||
}
|
||||
|
||||
this._cache.set(key, p)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
get(key, attempt = 1) {
|
||||
const p = this._cache.get(key)
|
||||
const jitter = (Math.random() * this._jitter) | 0
|
||||
|
||||
if (p) {
|
||||
// known - use adaptive with linear backoff
|
||||
const base = p.avg + (p.variance << 1)
|
||||
const backoff = base * attempt
|
||||
return Math.min(Math.max(backoff + jitter, this._min), this._max)
|
||||
} else {
|
||||
// unknown - use aggressive fallback
|
||||
const base = this._fallback[Math.min(attempt - 1, this._fallback.length - 1)]
|
||||
return base + jitter
|
||||
}
|
||||
}
|
||||
|
||||
has(key) {
|
||||
return this._cache.has(key)
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
return this._cache.delete(key)
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._cache.clear()
|
||||
}
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"name": "adaptive-timeout",
|
||||
"version": "1.0.1",
|
||||
"description": "adaptive-timeout",
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
"./package": "./package.json",
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"package.json",
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"devDependencies": {
|
||||
"brittle": "^3.19.0",
|
||||
"lunte": "^1.2.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-config-holepunch": "^2.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier . --write",
|
||||
"test": "prettier . --check && lunte && brittle-bare test/index.js",
|
||||
"lint": "lunte"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/holepunchto/adaptive-timeout.git"
|
||||
},
|
||||
"author": "Holepunch Inc",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/holepunchto/adaptive-timeout/issues"
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/adaptive-timeout",
|
||||
"dependencies": {
|
||||
"xache": "^1.2.1"
|
||||
}
|
||||
}
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
# Buffer for Array
|
||||
|
||||
Buffer for Array (B4A) provides a set of functions for bridging the gap between the Node.js `Buffer` class and the `Uint8Array` class. A browser compatibility layer is also included, making it possible to use B4A in both Node.js and browsers without having to worry about whether you're dealing with buffers or typed arrays.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm i b4a
|
||||
```
|
||||
|
||||
### React Native
|
||||
|
||||
When imported from React Native `b4a` will make use of `react-native-b4a` for optimised buffer operations when available. All you need to do is install it:
|
||||
|
||||
```sh
|
||||
npm i react-native-b4a
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### `b4a.isBuffer(value)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferisbufferobj
|
||||
|
||||
This will also return `true` when passed a `Uint8Array`.
|
||||
|
||||
#### `b4a.isEncoding(encoding)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferisencodingencoding
|
||||
|
||||
#### `b4a.alloc(size[, fill[, encoding]])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferallocsize-fill-encoding
|
||||
|
||||
#### `b4a.allocUnsafe(size)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferallocunsafesize
|
||||
|
||||
#### `b4a.allocUnsafeSlow(size)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferallocunsafeslowsize
|
||||
|
||||
#### `b4a.byteLength(string)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferbytelengthstring-encoding
|
||||
|
||||
#### `b4a.compare(buf1, buf2)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-buffercomparebuf1-buf2
|
||||
|
||||
#### `b4a.concat(buffers[, totalLength])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferconcatlist-totallength
|
||||
|
||||
#### `b4a.copy(source, target[, targetStart[, sourceStart[, sourceEnd]]])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufcopytarget-targetstart-sourcestart-sourceend
|
||||
|
||||
#### `b4a.equals(buf1, buf2)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufequalsotherbuffer
|
||||
|
||||
#### `b4a.fill(buffer, value[, offset[, end]][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#buffillvalue-offset-end-encoding
|
||||
|
||||
#### `b4a.from(array)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferfromarray
|
||||
|
||||
#### `b4a.from(arrayBuffer[, byteOffset[, length]])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferfromarraybuffer-byteoffset-length
|
||||
|
||||
#### `b4a.from(buffer)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferfrombuffer
|
||||
|
||||
#### `b4a.from(string[, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#static-method-bufferfromstring-encoding
|
||||
|
||||
#### `b4a.includes(buffer, value[, byteOffset][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufincludesvalue-byteoffset-encoding
|
||||
|
||||
#### `b4a.indexOf(buffer, value[, byteOffset][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufindexofvalue-byteoffset-encoding
|
||||
|
||||
#### `b4a.lastIndexOf(buffer, value[, byteOffset][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#buflastindexofvalue-byteoffset-encoding
|
||||
|
||||
#### `b4a.swap16(buffer)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufswap16
|
||||
|
||||
#### `b4a.swap32(buffer)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufswap32
|
||||
|
||||
#### `b4a.swap64(buffer)`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufswap64
|
||||
|
||||
#### `b4a.toBuffer(buffer)`
|
||||
|
||||
Convert a buffer to its canonical representation. In Node.js, the canonical representation is a `Buffer`. In the browser, the canonical representation is a `Uint8Array`.
|
||||
|
||||
#### `b4a.toString(buffer, [encoding[, start[, end]]])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#buftostringencoding-start-end
|
||||
|
||||
#### `b4a.write(buffer, string[, offset[, length]][, encoding])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufwritestring-offset-length-encoding
|
||||
|
||||
#### `b4a.writeDoubleLE(buffer, value[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufwritedoublelevalue-offset
|
||||
|
||||
#### `b4a.writeFloatLE(buffer, value[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufwritefloatlevalue-offset
|
||||
|
||||
#### `b4a.writeUInt32LE(buffer, value[, offset])`
|
||||
|
||||
https://nodejs.org/api/buffer.html#bufwriteuint32levalue-offset
|
||||
|
||||
#### `b4a.writeInt32LE(buffer, value[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufwriteint32levalue-offset
|
||||
|
||||
#### `b4a.readDoubleLE(buffer[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufreaddoubleleoffset
|
||||
|
||||
#### `b4a.readFloatLE(buffer[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufreadfloatleoffset
|
||||
|
||||
#### `b4a.readUInt32LE(buffer[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufreaduint32leoffset
|
||||
|
||||
#### `b4a.readInt32LE(buffer[, offset])`
|
||||
|
||||
See https://nodejs.org/api/buffer.html#bufreadint32leoffset
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0
|
||||
-567
@@ -1,567 +0,0 @@
|
||||
const ascii = require('./lib/ascii')
|
||||
const base64 = require('./lib/base64')
|
||||
const hex = require('./lib/hex')
|
||||
const latin1 = require('./lib/latin1')
|
||||
const utf8 = require('./lib/utf8')
|
||||
const utf16le = require('./lib/utf16le')
|
||||
|
||||
const LE = new Uint8Array(Uint16Array.of(0xff).buffer)[0] === 0xff
|
||||
|
||||
function codecFor(encoding) {
|
||||
switch (encoding) {
|
||||
case 'ascii':
|
||||
return ascii
|
||||
case 'base64':
|
||||
return base64
|
||||
case 'hex':
|
||||
return hex
|
||||
case 'binary':
|
||||
case 'latin1':
|
||||
return latin1
|
||||
case 'utf8':
|
||||
case 'utf-8':
|
||||
case undefined:
|
||||
case null:
|
||||
return utf8
|
||||
case 'ucs2':
|
||||
case 'ucs-2':
|
||||
case 'utf16le':
|
||||
case 'utf-16le':
|
||||
return utf16le
|
||||
default:
|
||||
throw new Error(`Unknown encoding '${encoding}'`)
|
||||
}
|
||||
}
|
||||
|
||||
function isBuffer(value) {
|
||||
return value instanceof Uint8Array
|
||||
}
|
||||
|
||||
function isEncoding(encoding) {
|
||||
try {
|
||||
codecFor(encoding)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function alloc(size, fill, encoding) {
|
||||
const buffer = new Uint8Array(size)
|
||||
if (fill !== undefined) {
|
||||
exports.fill(buffer, fill, 0, buffer.byteLength, encoding)
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
function allocUnsafe(size) {
|
||||
return new Uint8Array(size)
|
||||
}
|
||||
|
||||
function allocUnsafeSlow(size) {
|
||||
return new Uint8Array(size)
|
||||
}
|
||||
|
||||
function byteLength(string, encoding) {
|
||||
return codecFor(encoding).byteLength(string)
|
||||
}
|
||||
|
||||
function compare(a, b) {
|
||||
if (a === b) return 0
|
||||
|
||||
const len = Math.min(a.byteLength, b.byteLength)
|
||||
|
||||
a = new DataView(a.buffer, a.byteOffset, a.byteLength)
|
||||
b = new DataView(b.buffer, b.byteOffset, b.byteLength)
|
||||
|
||||
let i = 0
|
||||
|
||||
for (let n = len - (len % 4); i < n; i += 4) {
|
||||
const x = a.getUint32(i, LE)
|
||||
const y = b.getUint32(i, LE)
|
||||
if (x !== y) break
|
||||
}
|
||||
|
||||
for (; i < len; i++) {
|
||||
const x = a.getUint8(i)
|
||||
const y = b.getUint8(i)
|
||||
if (x < y) return -1
|
||||
if (x > y) return 1
|
||||
}
|
||||
|
||||
return a.byteLength > b.byteLength ? 1 : a.byteLength < b.byteLength ? -1 : 0
|
||||
}
|
||||
|
||||
function concat(buffers, length) {
|
||||
if (length === undefined) {
|
||||
length = buffers.reduce((len, buffer) => len + buffer.byteLength, 0)
|
||||
}
|
||||
|
||||
const result = new Uint8Array(length)
|
||||
|
||||
let offset = 0
|
||||
|
||||
for (const buffer of buffers) {
|
||||
if (offset + buffer.byteLength > result.byteLength) {
|
||||
result.set(buffer.subarray(0, result.byteLength - offset), offset)
|
||||
return result
|
||||
}
|
||||
|
||||
result.set(buffer, offset)
|
||||
offset += buffer.byteLength
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function copy(
|
||||
source,
|
||||
target,
|
||||
targetStart = 0,
|
||||
sourceStart = 0,
|
||||
sourceEnd = source.byteLength
|
||||
) {
|
||||
if (targetStart < 0) targetStart = 0
|
||||
if (targetStart >= target.byteLength) return 0
|
||||
|
||||
const targetLength = target.byteLength - targetStart
|
||||
|
||||
if (sourceStart < 0) sourceStart = 0
|
||||
if (sourceStart >= source.byteLength) return 0
|
||||
|
||||
if (sourceEnd <= sourceStart) return 0
|
||||
if (sourceEnd > source.byteLength) sourceEnd = source.byteLength
|
||||
|
||||
if (sourceEnd - sourceStart > targetLength) {
|
||||
sourceEnd = sourceStart + targetLength
|
||||
}
|
||||
|
||||
const sourceLength = sourceEnd - sourceStart
|
||||
|
||||
if (source === target) {
|
||||
target.copyWithin(targetStart, sourceStart, sourceEnd)
|
||||
} else {
|
||||
if (sourceStart !== 0 || sourceEnd !== source.byteLength) {
|
||||
source = source.subarray(sourceStart, sourceEnd)
|
||||
}
|
||||
|
||||
target.set(source, targetStart)
|
||||
}
|
||||
|
||||
return sourceLength
|
||||
}
|
||||
|
||||
function equals(a, b) {
|
||||
if (a === b) return true
|
||||
if (a.byteLength !== b.byteLength) return false
|
||||
|
||||
return compare(a, b) === 0
|
||||
}
|
||||
|
||||
function fill(
|
||||
buffer,
|
||||
value,
|
||||
offset = 0,
|
||||
end = buffer.byteLength,
|
||||
encoding = 'utf8'
|
||||
) {
|
||||
if (typeof value === 'string') {
|
||||
if (typeof offset === 'string') {
|
||||
// fill(string, encoding)
|
||||
encoding = offset
|
||||
offset = 0
|
||||
end = buffer.byteLength
|
||||
} else if (typeof end === 'string') {
|
||||
// fill(string, offset, encoding)
|
||||
encoding = end
|
||||
end = buffer.byteLength
|
||||
}
|
||||
} else if (typeof value === 'number') {
|
||||
value = value & 0xff
|
||||
} else if (typeof value === 'boolean') {
|
||||
value = +value
|
||||
}
|
||||
|
||||
if (offset < 0) offset = 0
|
||||
if (offset >= buffer.byteLength) return buffer
|
||||
|
||||
if (end <= offset) return buffer
|
||||
if (end > buffer.byteLength) end = buffer.byteLength
|
||||
|
||||
if (typeof value === 'number') return buffer.fill(value, offset, end)
|
||||
|
||||
if (typeof value === 'string') value = exports.from(value, encoding)
|
||||
|
||||
const len = value.byteLength
|
||||
|
||||
for (let i = 0, n = end - offset; i < n; ++i) {
|
||||
buffer[i + offset] = value[i % len]
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function from(value, encodingOrOffset, length) {
|
||||
// from(string, encoding)
|
||||
if (typeof value === 'string') return fromString(value, encodingOrOffset)
|
||||
|
||||
// from(array)
|
||||
if (Array.isArray(value)) return fromArray(value)
|
||||
|
||||
// from(buffer)
|
||||
if (ArrayBuffer.isView(value)) return fromBuffer(value)
|
||||
|
||||
// from(arrayBuffer[, byteOffset[, length]])
|
||||
return fromArrayBuffer(value, encodingOrOffset, length)
|
||||
}
|
||||
|
||||
function fromString(string, encoding) {
|
||||
const codec = codecFor(encoding)
|
||||
const buffer = new Uint8Array(codec.byteLength(string))
|
||||
codec.write(buffer, string)
|
||||
return buffer
|
||||
}
|
||||
|
||||
function fromArray(array) {
|
||||
const buffer = new Uint8Array(array.length)
|
||||
buffer.set(array)
|
||||
return buffer
|
||||
}
|
||||
|
||||
function fromBuffer(buffer) {
|
||||
const copy = new Uint8Array(buffer.byteLength)
|
||||
copy.set(buffer)
|
||||
return copy
|
||||
}
|
||||
|
||||
function fromArrayBuffer(arrayBuffer, byteOffset, length) {
|
||||
return new Uint8Array(arrayBuffer, byteOffset, length)
|
||||
}
|
||||
|
||||
function includes(buffer, value, byteOffset, encoding) {
|
||||
return indexOf(buffer, value, byteOffset, encoding) !== -1
|
||||
}
|
||||
|
||||
function indexOf(buffer, value, byteOffset, encoding) {
|
||||
return bidirectionalIndexOf(
|
||||
buffer,
|
||||
value,
|
||||
byteOffset,
|
||||
encoding,
|
||||
true /* first */
|
||||
)
|
||||
}
|
||||
|
||||
function lastIndexOf(buffer, value, byteOffset, encoding) {
|
||||
return bidirectionalIndexOf(
|
||||
buffer,
|
||||
value,
|
||||
byteOffset,
|
||||
encoding,
|
||||
false /* last */
|
||||
)
|
||||
}
|
||||
|
||||
function bidirectionalIndexOf(buffer, value, byteOffset, encoding, first) {
|
||||
if (buffer.byteLength === 0) return -1
|
||||
|
||||
if (typeof byteOffset === 'string') {
|
||||
encoding = byteOffset
|
||||
byteOffset = 0
|
||||
} else if (byteOffset === undefined) {
|
||||
byteOffset = first ? 0 : buffer.length - 1
|
||||
} else if (byteOffset < 0) {
|
||||
byteOffset += buffer.byteLength
|
||||
}
|
||||
|
||||
if (byteOffset >= buffer.byteLength) {
|
||||
if (first) return -1
|
||||
else byteOffset = buffer.byteLength - 1
|
||||
} else if (byteOffset < 0) {
|
||||
if (first) byteOffset = 0
|
||||
else return -1
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
value = from(value, encoding)
|
||||
} else if (typeof value === 'number') {
|
||||
value = value & 0xff
|
||||
|
||||
if (first) {
|
||||
return buffer.indexOf(value, byteOffset)
|
||||
} else {
|
||||
return buffer.lastIndexOf(value, byteOffset)
|
||||
}
|
||||
}
|
||||
|
||||
if (value.byteLength === 0) return -1
|
||||
|
||||
if (first) {
|
||||
let foundIndex = -1
|
||||
|
||||
for (let i = byteOffset; i < buffer.byteLength; i++) {
|
||||
if (buffer[i] === value[foundIndex === -1 ? 0 : i - foundIndex]) {
|
||||
if (foundIndex === -1) foundIndex = i
|
||||
if (i - foundIndex + 1 === value.byteLength) return foundIndex
|
||||
} else {
|
||||
if (foundIndex !== -1) i -= i - foundIndex
|
||||
foundIndex = -1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (byteOffset + value.byteLength > buffer.byteLength) {
|
||||
byteOffset = buffer.byteLength - value.byteLength
|
||||
}
|
||||
|
||||
for (let i = byteOffset; i >= 0; i--) {
|
||||
let found = true
|
||||
|
||||
for (let j = 0; j < value.byteLength; j++) {
|
||||
if (buffer[i + j] !== value[j]) {
|
||||
found = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (found) return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
function swap(buffer, n, m) {
|
||||
const i = buffer[n]
|
||||
buffer[n] = buffer[m]
|
||||
buffer[m] = i
|
||||
}
|
||||
|
||||
function swap16(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
if (len % 2 !== 0)
|
||||
throw new RangeError('Buffer size must be a multiple of 16-bits')
|
||||
|
||||
for (let i = 0; i < len; i += 2) swap(buffer, i, i + 1)
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function swap32(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
if (len % 4 !== 0)
|
||||
throw new RangeError('Buffer size must be a multiple of 32-bits')
|
||||
|
||||
for (let i = 0; i < len; i += 4) {
|
||||
swap(buffer, i, i + 3)
|
||||
swap(buffer, i + 1, i + 2)
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function swap64(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
if (len % 8 !== 0)
|
||||
throw new RangeError('Buffer size must be a multiple of 64-bits')
|
||||
|
||||
for (let i = 0; i < len; i += 8) {
|
||||
swap(buffer, i, i + 7)
|
||||
swap(buffer, i + 1, i + 6)
|
||||
swap(buffer, i + 2, i + 5)
|
||||
swap(buffer, i + 3, i + 4)
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function toBuffer(buffer) {
|
||||
return buffer
|
||||
}
|
||||
|
||||
function toString(
|
||||
buffer,
|
||||
encoding = 'utf8',
|
||||
start = 0,
|
||||
end = buffer.byteLength
|
||||
) {
|
||||
// toString(buffer)
|
||||
if (arguments.length === 1) return utf8.toString(buffer)
|
||||
|
||||
// toString(buffer, encoding)
|
||||
if (arguments.length === 2) return codecFor(encoding).toString(buffer)
|
||||
|
||||
if (start < 0) start = 0
|
||||
if (start >= buffer.byteLength) return ''
|
||||
|
||||
if (end <= start) return ''
|
||||
if (end > buffer.byteLength) end = buffer.byteLength
|
||||
|
||||
if (start !== 0 || end !== buffer.byteLength) {
|
||||
buffer = buffer.subarray(start, end)
|
||||
}
|
||||
|
||||
return codecFor(encoding).toString(buffer)
|
||||
}
|
||||
|
||||
function write(buffer, string, offset, length, encoding) {
|
||||
// write(buffer, string)
|
||||
if (arguments.length === 2) return utf8.write(buffer, string)
|
||||
|
||||
if (typeof offset === 'string') {
|
||||
// write(buffer, string, encoding)
|
||||
encoding = offset
|
||||
offset = 0
|
||||
length = buffer.byteLength
|
||||
} else if (typeof length === 'string') {
|
||||
// write(buffer, string, offset, encoding)
|
||||
encoding = length
|
||||
length = buffer.byteLength - offset
|
||||
}
|
||||
|
||||
length = Math.min(length, exports.byteLength(string, encoding))
|
||||
|
||||
let start = offset
|
||||
if (start < 0) start = 0
|
||||
if (start >= buffer.byteLength) return 0
|
||||
|
||||
let end = offset + length
|
||||
if (end <= start) return 0
|
||||
if (end > buffer.byteLength) end = buffer.byteLength
|
||||
|
||||
if (start !== 0 || end !== buffer.byteLength) {
|
||||
buffer = buffer.subarray(start, end)
|
||||
}
|
||||
|
||||
return codecFor(encoding).write(buffer, string)
|
||||
}
|
||||
|
||||
function readDoubleBE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getFloat64(offset, false)
|
||||
}
|
||||
|
||||
function readDoubleLE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getFloat64(offset, true)
|
||||
}
|
||||
|
||||
function readFloatBE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getFloat32(offset, false)
|
||||
}
|
||||
|
||||
function readFloatLE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getFloat32(offset, true)
|
||||
}
|
||||
|
||||
function readInt32BE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getInt32(offset, false)
|
||||
}
|
||||
|
||||
function readInt32LE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getInt32(offset, true)
|
||||
}
|
||||
|
||||
function readUInt32BE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getUint32(offset, false)
|
||||
}
|
||||
|
||||
function readUInt32LE(buffer, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
return view.getUint32(offset, true)
|
||||
}
|
||||
|
||||
function writeDoubleBE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setFloat64(offset, value, false)
|
||||
return offset + 8
|
||||
}
|
||||
|
||||
function writeDoubleLE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setFloat64(offset, value, true)
|
||||
return offset + 8
|
||||
}
|
||||
|
||||
function writeFloatBE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setFloat32(offset, value, false)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeFloatLE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setFloat32(offset, value, true)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeInt32BE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setInt32(offset, value, false)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeInt32LE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setInt32(offset, value, true)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeUInt32BE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setUint32(offset, value, false)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
function writeUInt32LE(buffer, value, offset = 0) {
|
||||
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
view.setUint32(offset, value, true)
|
||||
return offset + 4
|
||||
}
|
||||
|
||||
module.exports = exports = {
|
||||
isBuffer,
|
||||
isEncoding,
|
||||
alloc,
|
||||
allocUnsafe,
|
||||
allocUnsafeSlow,
|
||||
byteLength,
|
||||
compare,
|
||||
concat,
|
||||
copy,
|
||||
equals,
|
||||
fill,
|
||||
from,
|
||||
includes,
|
||||
indexOf,
|
||||
lastIndexOf,
|
||||
swap16,
|
||||
swap32,
|
||||
swap64,
|
||||
toBuffer,
|
||||
toString,
|
||||
write,
|
||||
readDoubleBE,
|
||||
readDoubleLE,
|
||||
readFloatBE,
|
||||
readFloatLE,
|
||||
readInt32BE,
|
||||
readInt32LE,
|
||||
readUInt32BE,
|
||||
readUInt32LE,
|
||||
writeDoubleBE,
|
||||
writeDoubleLE,
|
||||
writeFloatBE,
|
||||
writeFloatLE,
|
||||
writeInt32BE,
|
||||
writeInt32LE,
|
||||
writeUInt32BE,
|
||||
writeUInt32LE
|
||||
}
|
||||
-188
@@ -1,188 +0,0 @@
|
||||
function isBuffer(value) {
|
||||
return Buffer.isBuffer(value) || value instanceof Uint8Array
|
||||
}
|
||||
|
||||
function isEncoding(encoding) {
|
||||
return Buffer.isEncoding(encoding)
|
||||
}
|
||||
|
||||
function alloc(size, fill, encoding) {
|
||||
return Buffer.alloc(size, fill, encoding)
|
||||
}
|
||||
|
||||
function allocUnsafe(size) {
|
||||
return Buffer.allocUnsafe(size)
|
||||
}
|
||||
|
||||
function allocUnsafeSlow(size) {
|
||||
return Buffer.allocUnsafeSlow(size)
|
||||
}
|
||||
|
||||
function byteLength(string, encoding) {
|
||||
return Buffer.byteLength(string, encoding)
|
||||
}
|
||||
|
||||
function compare(a, b) {
|
||||
return Buffer.compare(a, b)
|
||||
}
|
||||
|
||||
function concat(buffers, totalLength) {
|
||||
return Buffer.concat(buffers, totalLength)
|
||||
}
|
||||
|
||||
function copy(source, target, targetStart, start, end) {
|
||||
return toBuffer(source).copy(target, targetStart, start, end)
|
||||
}
|
||||
|
||||
function equals(a, b) {
|
||||
return toBuffer(a).equals(b)
|
||||
}
|
||||
|
||||
function fill(buffer, value, offset, end, encoding) {
|
||||
return toBuffer(buffer).fill(value, offset, end, encoding)
|
||||
}
|
||||
|
||||
function from(value, encodingOrOffset, length) {
|
||||
return Buffer.from(value, encodingOrOffset, length)
|
||||
}
|
||||
|
||||
function includes(buffer, value, byteOffset, encoding) {
|
||||
return toBuffer(buffer).includes(value, byteOffset, encoding)
|
||||
}
|
||||
|
||||
function indexOf(buffer, value, byfeOffset, encoding) {
|
||||
return toBuffer(buffer).indexOf(value, byfeOffset, encoding)
|
||||
}
|
||||
|
||||
function lastIndexOf(buffer, value, byteOffset, encoding) {
|
||||
return toBuffer(buffer).lastIndexOf(value, byteOffset, encoding)
|
||||
}
|
||||
|
||||
function swap16(buffer) {
|
||||
return toBuffer(buffer).swap16()
|
||||
}
|
||||
|
||||
function swap32(buffer) {
|
||||
return toBuffer(buffer).swap32()
|
||||
}
|
||||
|
||||
function swap64(buffer) {
|
||||
return toBuffer(buffer).swap64()
|
||||
}
|
||||
|
||||
function toBuffer(buffer) {
|
||||
if (Buffer.isBuffer(buffer)) return buffer
|
||||
return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
||||
}
|
||||
|
||||
function toString(buffer, encoding, start, end) {
|
||||
return toBuffer(buffer).toString(encoding, start, end)
|
||||
}
|
||||
|
||||
function write(buffer, string, offset, length, encoding) {
|
||||
return toBuffer(buffer).write(string, offset, length, encoding)
|
||||
}
|
||||
|
||||
function readDoubleBE(buffer, offset) {
|
||||
return toBuffer(buffer).readDoubleBE(offset)
|
||||
}
|
||||
|
||||
function readDoubleLE(buffer, offset) {
|
||||
return toBuffer(buffer).readDoubleLE(offset)
|
||||
}
|
||||
|
||||
function readFloatBE(buffer, offset) {
|
||||
return toBuffer(buffer).readFloatBE(offset)
|
||||
}
|
||||
|
||||
function readFloatLE(buffer, offset) {
|
||||
return toBuffer(buffer).readFloatLE(offset)
|
||||
}
|
||||
|
||||
function readInt32BE(buffer, offset) {
|
||||
return toBuffer(buffer).readInt32BE(offset)
|
||||
}
|
||||
|
||||
function readInt32LE(buffer, offset) {
|
||||
return toBuffer(buffer).readInt32LE(offset)
|
||||
}
|
||||
|
||||
function readUInt32BE(buffer, offset) {
|
||||
return toBuffer(buffer).readUInt32BE(offset)
|
||||
}
|
||||
|
||||
function readUInt32LE(buffer, offset) {
|
||||
return toBuffer(buffer).readUInt32LE(offset)
|
||||
}
|
||||
|
||||
function writeDoubleBE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeDoubleBE(value, offset)
|
||||
}
|
||||
|
||||
function writeDoubleLE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeDoubleLE(value, offset)
|
||||
}
|
||||
|
||||
function writeFloatBE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeFloatBE(value, offset)
|
||||
}
|
||||
|
||||
function writeFloatLE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeFloatLE(value, offset)
|
||||
}
|
||||
|
||||
function writeInt32BE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeInt32BE(value, offset)
|
||||
}
|
||||
|
||||
function writeInt32LE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeInt32LE(value, offset)
|
||||
}
|
||||
|
||||
function writeUInt32BE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeUInt32BE(value, offset)
|
||||
}
|
||||
|
||||
function writeUInt32LE(buffer, value, offset) {
|
||||
return toBuffer(buffer).writeUInt32LE(value, offset)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isBuffer,
|
||||
isEncoding,
|
||||
alloc,
|
||||
allocUnsafe,
|
||||
allocUnsafeSlow,
|
||||
byteLength,
|
||||
compare,
|
||||
concat,
|
||||
copy,
|
||||
equals,
|
||||
fill,
|
||||
from,
|
||||
includes,
|
||||
indexOf,
|
||||
lastIndexOf,
|
||||
swap16,
|
||||
swap32,
|
||||
swap64,
|
||||
toBuffer,
|
||||
toString,
|
||||
write,
|
||||
readDoubleBE,
|
||||
readDoubleLE,
|
||||
readFloatBE,
|
||||
readFloatLE,
|
||||
readInt32BE,
|
||||
readInt32LE,
|
||||
readUInt32BE,
|
||||
readUInt32LE,
|
||||
writeDoubleBE,
|
||||
writeDoubleLE,
|
||||
writeFloatBE,
|
||||
writeFloatLE,
|
||||
writeInt32BE,
|
||||
writeInt32LE,
|
||||
writeUInt32BE,
|
||||
writeUInt32LE
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
function byteLength(string) {
|
||||
return string.length
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let result = ''
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
result += String.fromCharCode(buffer[i] & 0x7f)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
buffer[i] = string.charCodeAt(i)
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
const alphabet =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
|
||||
const codes = new Uint8Array(256)
|
||||
|
||||
for (let i = 0; i < alphabet.length; i++) {
|
||||
codes[alphabet.charCodeAt(i)] = i
|
||||
}
|
||||
|
||||
codes[/* - */ 0x2d] = 62
|
||||
codes[/* _ */ 0x5f] = 63
|
||||
|
||||
function byteLength(string) {
|
||||
let len = string.length
|
||||
|
||||
if (string.charCodeAt(len - 1) === 0x3d) len--
|
||||
if (len > 1 && string.charCodeAt(len - 1) === 0x3d) len--
|
||||
|
||||
return (len * 3) >>> 2
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let result = ''
|
||||
|
||||
for (let i = 0; i < len; i += 3) {
|
||||
result +=
|
||||
alphabet[buffer[i] >> 2] +
|
||||
alphabet[((buffer[i] & 3) << 4) | (buffer[i + 1] >> 4)] +
|
||||
alphabet[((buffer[i + 1] & 15) << 2) | (buffer[i + 2] >> 6)] +
|
||||
alphabet[buffer[i + 2] & 63]
|
||||
}
|
||||
|
||||
if (len % 3 === 2) {
|
||||
result = result.substring(0, result.length - 1) + '='
|
||||
} else if (len % 3 === 1) {
|
||||
result = result.substring(0, result.length - 2) + '=='
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
for (let i = 0, j = 0; j < len; i += 4) {
|
||||
const a = codes[string.charCodeAt(i)]
|
||||
const b = codes[string.charCodeAt(i + 1)]
|
||||
const c = codes[string.charCodeAt(i + 2)]
|
||||
const d = codes[string.charCodeAt(i + 3)]
|
||||
|
||||
buffer[j++] = (a << 2) | (b >> 4)
|
||||
buffer[j++] = ((b & 15) << 4) | (c >> 2)
|
||||
buffer[j++] = ((c & 3) << 6) | (d & 63)
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
function byteLength(string) {
|
||||
return string.length >>> 1
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
buffer = new DataView(buffer.buffer, buffer.byteOffset, len)
|
||||
|
||||
let result = ''
|
||||
let i = 0
|
||||
|
||||
for (let n = len - (len % 4); i < n; i += 4) {
|
||||
result += buffer.getUint32(i).toString(16).padStart(8, '0')
|
||||
}
|
||||
|
||||
for (; i < len; i++) {
|
||||
result += buffer.getUint8(i).toString(16).padStart(2, '0')
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const a = hexValue(string.charCodeAt(i * 2))
|
||||
const b = hexValue(string.charCodeAt(i * 2 + 1))
|
||||
|
||||
if (a === undefined || b === undefined) {
|
||||
return buffer.subarray(0, i)
|
||||
}
|
||||
|
||||
buffer[i] = (a << 4) | b
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
|
||||
function hexValue(char) {
|
||||
if (char >= 0x30 && char <= 0x39) return char - 0x30
|
||||
if (char >= 0x41 && char <= 0x46) return char - 0x41 + 10
|
||||
if (char >= 0x61 && char <= 0x66) return char - 0x61 + 10
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
function byteLength(string) {
|
||||
return string.length
|
||||
}
|
||||
|
||||
function toString(buffer) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
let result = ''
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
result += String.fromCharCode(buffer[i])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function write(buffer, string) {
|
||||
const len = buffer.byteLength
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
buffer[i] = string.charCodeAt(i)
|
||||
}
|
||||
|
||||
return len
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
byteLength,
|
||||
toString,
|
||||
write
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user