Pear API Base Class (Holepunch)
The `pear-api` package provides the foundational base class for interacting with the Pear API, which is part of the Holepunch peer-to-peer (P2P) runtime and development platform. Currently at version 1.30.0, this library enables developers to build P2P applications, particularly focusing on User Interface integrations by abstracting complex underlying P2P mechanisms. The Pear ecosystem is actively maintained, with regular updates to its 1.x branch and a significant transition underway to a version 2, which introduces notable breaking changes and a shift towards modern JavaScript module standards. Key differentiators include its focus on enabling local-first, offline-first P2P applications and its design for extensibility within UI environments like Electron.
Common errors
-
TypeError: Class constructor PearAPI cannot be invoked without 'new'
cause Attempting to call `PearAPI()` directly instead of instantiating it with the `new` keyword.fixAlways instantiate the `PearAPI` class (or its subclasses) using `new`, e.g., `const api = new PearAPI();` or `class MyAPI extends PearAPI { ... }` then `new MyAPI();`. -
ReferenceError: PearAPI is not defined
cause This typically occurs in a CommonJS environment when an ESM-only version of `pear-api` is used, or the `PearAPI` class was not correctly imported.fixVerify that your module import statement is correct (`import { PearAPI } from 'pear-api';`). If you are in a CommonJS context and need an ESM-only module, consider migrating your project to ESM or using dynamic `import()` within an `async` function. -
Error: Authentication failed: Invalid API key or token
cause The base `PearAPI` or its derived classes often require an authentication token or key, which was either missing, expired, or invalid during initialization or an API call.fixEnsure that your API key or token is correctly provided during the `PearAPI` constructor or connection method. Double-check its validity, expiration, and required permissions according to your Pear API provider's documentation. Use environment variables for sensitive credentials.
Warnings
- breaking Migrating from Pear v1 to v2 involves significant breaking changes. Specifically, many UI-related methods have been moved or renamed, and the application entrypoint has changed from supporting HTML in v1 to only JavaScript in v2.
- deprecated The `pear run` CLI command has been deprecated in favor of using the `pear-runtime` module for embeddable runtimes with P2P Over-The-Air (OTA) updates.
- gotcha Future major versions of Pear modules, including `pear-api`, are increasingly adopting an ESM-only (ECMAScript Modules) export strategy. Projects using CommonJS (`require()`) might encounter `ERR_REQUIRE_ESM`.
- gotcha The `pear-api` package, as a base class for P2P applications, requires careful handling of resource cleanup (e.g., network connections, database instances) during application teardown to prevent hanging processes or resource locks.
Install
-
npm install pear-api -
yarn add pear-api -
pnpm add pear-api
Imports
- PearAPI
const PearAPI = require('pear-api');import { PearAPI } from 'pear-api'; - Config
import Config from 'pear-api/config';
import { Config } from 'pear-api'; - PearError
const { PearError } = require('pear-api');import { PearError } from 'pear-api';
Quickstart
import { PearAPI } from 'pear-api';
interface MyApiOptions {
authToken: string;
appId: string;
}
interface MyP2PData {
id: string;
message: string;
timestamp: number;
}
class MyPearAppAPI extends PearAPI {
private token: string;
private appId: string;
constructor(options: MyApiOptions) {
super(); // Initialize the base PearAPI class
this.token = options.authToken;
this.appId = options.appId;
console.log(`MyPearAppAPI initialized for app: ${this.appId}`);
}
async connect(): Promise<boolean> {
console.log('Attempting to connect to Pear network...');
// Simulate P2P network connection logic
await new Promise(resolve => setTimeout(resolve, 1000));
if (!this.token) {
console.error('Authentication token is missing.');
return false;
}
console.log('Successfully connected to Pear network.');
return true;
}
async publishData(data: MyP2PData): Promise<void> {
if (!(await this.connect())) {
throw new Error('Failed to connect, cannot publish data.');
}
console.log(`Publishing data [${data.id}]: ${data.message} at ${new Date(data.timestamp).toISOString()}`);
// Simulate data publishing to the P2P network
await new Promise(resolve => setTimeout(resolve, 500));
console.log('Data published.');
}
static async createAndRun(token: string): Promise<MyPearAppAPI> {
const api = new MyPearAppAPI({ authToken: token, appId: 'my-p2p-app' });
const connected = await api.connect();
if (connected) {
await api.publishData({ id: 'msg-1', message: 'Hello P2P world!', timestamp: Date.now() });
}
return api;
}
}
// Example usage with a dummy token
MyPearAppAPI.createAndRun(process.env.PEAR_AUTH_TOKEN ?? 'dummy_auth_token_123')
.then(() => console.log('Pear application flow completed.'))
.catch(error => console.error('Pear application error:', error.message));