import pear -> global.Pear

This commit is contained in:
dmc
2024-01-29 14:33:45 +01:00
parent d2cfd9762f
commit a2dbb32d51
2 changed files with 82 additions and 89 deletions

View File

@@ -133,10 +133,11 @@ npm i hyperswarm hypercore-crypto b4a
Replace `app.js` with Replace `app.js` with
``` js ``` js
import { teardown } from 'pear' /* global Pear */
import Hyperswarm from 'hyperswarm' import Hyperswarm from 'hyperswarm'
import crypto from 'hypercore-crypto' import crypto from 'hypercore-crypto'
import b4a from 'b4a' import b4a from 'b4a'
const { teardown } = Pear
const swarm = new Hyperswarm() const swarm = new Hyperswarm()

View File

@@ -7,54 +7,48 @@ Most application peer-to-peer functionality is provided by ecosystem modules rat
Platform APIs are unchangable. Compatiblity cannot break. So the Pear API surface aims to be (and remain) Platform APIs are unchangable. Compatiblity cannot break. So the Pear API surface aims to be (and remain)
as small as possible. as small as possible.
## `import pear from 'pear'` ## `global.Pear`
To use the Pear Platform API: import `pear`. The Pear Platform API is made available globally as `Pear`.
```js The `Pear` API is designed to be small and immutable.
import pear from 'pear'
```
Import namespaces are also supported, for example: Any future changes to the `Pear` API will be non-breaking additions.
```js ## `Pear.config <Object>`
import { config } from 'pear'
```
## `pear.config <Object>`
Contains application configuration data. Contains application configuration data.
### `pear.config.key <Object|null>` ### `Pear.config.key <Object|null>`
The application key, `null` in development mode. The application key, `null` in development mode.
The `config.key` object holds both Hexadecimal and Z-Base-32 encodings of the key, and is of the form `{ z32: <String>, hex: <String> }`, The `config.key` object holds both Hexadecimal and Z-Base-32 encodings of the key, and is of the form `{ z32: <String>, hex: <String> }`,
### `pear.config.dev <Boolean>` ### `Pear.config.dev <Boolean>`
Whether application is in development mode Whether application is in development mode
### `pear.config.tier <String>` ### `Pear.config.tier <String>`
Runtime scenario (dev, staging or production) Runtime scenario (dev, staging or production)
### `pear.config.storage <String>` ### `Pear.config.storage <String>`
Application storage path Application storage path
### `pear.config.name <String>` ### `Pear.config.name <String>`
Application name Application name
### `pear.config.main <String>` ### `Pear.config.main <String>`
Application entry file Application entry file
### `pear.config.channel <String|null>` ### `Pear.config.channel <String|null>`
Application release/staging channel, `null` in development mode. Application release/staging channel, `null` in development mode.
### `pear.config.options <Object>` ### `Pear.config.options <Object>`
Configuration options. Configuration options.
The `pear` configuration object as supplied via an applications `package.json` file. The `pear` configuration object as supplied via an applications `package.json` file.
@@ -63,35 +57,35 @@ The `pear` configuration object as supplied via an applications `package.json` f
* [Configuration](./configuration.md) * [Configuration](./configuration.md)
### `pear.config.env <Object>` ### `Pear.config.env <Object>`
The environment variables that an application was started with, as key-value pairs in an object. The environment variables that an application was started with, as key-value pairs in an object.
### `pear.config.cwd <String>` ### `Pear.config.cwd <String>`
The current working directory that an application was started from. The current working directory that an application was started from.
### `pear.config.flags <Object>` ### `Pear.config.flags <Object>`
Parsed command-line flag values as supplied when an application was started. Parsed command-line flag values as supplied when an application was started.
### `pear.config.tools <Boolean>` ### `Pear.config.tools <Boolean>`
Indicates whether or not Devtools is enabled. Indicates whether or not Devtools is enabled.
### `pear.config.watch <Boolean>` ### `Pear.config.watch <Boolean>`
Indicates whether or not Watch-Reload functionality is enabled. Indicates whether or not Watch-Reload functionality is enabled.
### `pear.config.storage <String>` ### `Pear.config.storage <String>`
Application storage path. Application storage path.
### `pear.config.args <Array>` ### `Pear.config.args <Array>`
Command-line application arguments passed after double dash `--`. Command-line application arguments passed after double dash `--`.
### `pear.config.release <Number>` ### `Pear.config.release <Number>`
The current release length as marked by the `pear release` command. The current release length as marked by the `pear release` command.
@@ -99,18 +93,18 @@ The current release length as marked by the `pear release` command.
* [`pear release`](./cli.md) * [`pear release`](./cli.md)
### `pear.config.link <String>` ### `Pear.config.link <String>`
The Pear link of an application. Takes the form `pear://<key>/<data>`. The Pear link of an application. Takes the form `pear://<key>/<data>`.
In development, `pear://dev/<data>`. In development, `pear://dev/<data>`.
**References** **References**
* [pear.config.link](#pearconfiglinkdata-string) * [Pear.config.link](#pearconfiglinkdata-string)
* [`pear dev`](./cli.md) * [`pear dev`](./cli.md)
* [`pear launch`](./cli.md) * [`pear launch`](./cli.md)
### `pear.config.linkData <String>` ### `Pear.config.linkData <String>`
Holds just the data portion of a Pear link. Holds just the data portion of a Pear link.
@@ -120,46 +114,46 @@ In development, `pear://dev/<data>`.
**References** **References**
* [pear.config.link](#pearconfiglink-string) * [Pear.config.link](#pearconfiglink-string)
* [`pear dev`](./cli.md) * [`pear dev`](./cli.md)
* [`pear launch`](./cli.md) * [`pear launch`](./cli.md)
### `pear.config.checkpoint <Any>` ### `Pear.config.checkpoint <Any>`
Holds state as set by `pear.checkpoint()`. When an application restarts it will hold the most recent value passed to `pear.checkpoint()`. Holds state as set by `Pear.checkpoint()`. When an application restarts it will hold the most recent value passed to `Pear.checkpoint()`.
Stores state that will be available as `pear.config.checkpoint` next time the application starts. Stores state that will be available as `Pear.config.checkpoint` next time the application starts.
The `pear.config.checkpoint` property immediately reflects the latest checkpoint. The `Pear.config.checkpoint` property immediately reflects the latest checkpoint.
The returned `Promise` will resolve once the checkpoint has been successfully stored. The returned `Promise` will resolve once the checkpoint has been successfully stored.
**References** **References**
* [pear.checkpoint()](#pear-checkpoint-any) * [Pear.checkpoint()](#pear-checkpoint-any)
### `pear.config.release <Integer>` ### `Pear.config.release <Integer>`
Application release sequence integer, `null` in development mode. Application release sequence integer, `null` in development mode.
### `pear.config.flags <Object>` ### `Pear.config.flags <Object>`
Parsed runtime flags. For internal/advanced use. Parsed runtime flags. For internal/advanced use.
## `pear.checkpoint(<Any>) => Promise` ## `Pear.checkpoint(<Any>) => Promise`
Stores state that will be available as `pear.config.checkpoint` next time the application starts. Stores state that will be available as `Pear.config.checkpoint` next time the application starts.
The `pear.config.checkpoint` property immediately reflects the latest checkpoint. The `Pear.config.checkpoint` property immediately reflects the latest checkpoint.
The returned `Promise` will resolve once the checkpoint has been successfully stored. The returned `Promise` will resolve once the checkpoint has been successfully stored.
**References** **References**
* [pear.config.checkpoint()](#pear--config-checkpoint-any) * [Pear.config.checkpoint()](#pear--config-checkpoint-any)
## pear.messages([ pattern ], [ listener ]) -> Iterable ## Pear.messages([ pattern ], [ listener ]) -> Iterable
A function which accepts a pattern object and returns an [`Iambus`](https://github.com/holepunchto/iambus) subscriber (which inherits from [`streamx`](https://github.com/mafintosh/streamx) `Readable`) which emits message objects matching a provided pattern object. A function which accepts a pattern object and returns an [`Iambus`](https://github.com/holepunchto/iambus) subscriber (which inherits from [`streamx`](https://github.com/mafintosh/streamx) `Readable`) which emits message objects matching a provided pattern object.
@@ -174,7 +168,7 @@ A message object may have any properties. Platform-generated messages are given
Listen for an internal platform message using a pattern object and listener function: Listen for an internal platform message using a pattern object and listener function:
```js ```js
import { messages } from 'pear' const { messages } = Pear
messages({ type: 'pear/wakeup' }, ({ data, link }) => { messages({ type: 'pear/wakeup' }, ({ data, link }) => {
console.log('pear/wakeup', data, link) console.log('pear/wakeup', data, link)
@@ -184,7 +178,7 @@ messages({ type: 'pear/wakeup' }, ({ data, link }) => {
Tiny utility module which logs all messages using `for await`: Tiny utility module which logs all messages using `for await`:
```js ```js
import { messages } from 'pear' const { messages } = Pear
for await (const message of messages()) { for await (const message of messages()) {
if (global.LOGBUS) console.log('BUS:', message) if (global.LOGBUS) console.log('BUS:', message)
@@ -194,7 +188,7 @@ for await (const message of messages()) {
Use `message` to create an application message: Use `message` to create an application message:
```js ```js
import { message, messages } from 'pear' const { message, messages } = Pear
const ctaClicks = message({ type: 'my-app/user-cta' }) const ctaClicks = message({ type: 'my-app/user-cta' })
@@ -206,12 +200,12 @@ onUserClickCta((event, data) => {
}) })
``` ```
## `await pear.message(<Object>)` ## `await Pear.message(<Object>)`
Send a message which will be: Send a message which will be:
```js ```js
import { message, messages } from 'pear' const { message, messages } = Pear
async function logMessages () { async function logMessages () {
for await (const message of messages()) console.log(message) for await (const message of messages()) console.log(message)
@@ -226,35 +220,35 @@ do {
} while (count++ < 1000) } while (count++ < 1000)
``` ```
## `pear.preferences <Function|Object>` ## `Pear.preferences <Function|Object>`
User preferences management. User preferences management.
### `for await (const [operation, key, value] of pear.preferences())` ### `for await (const [operation, key, value] of Pear.preferences())`
An async iterable that yields arrays containing `operation <String>`, `key <String>` and `value <any>`. An async iterable that yields arrays containing `operation <String>`, `key <String>` and `value <any>`.
Watch for application updates. The `operation` may be `set` or `del`. In the case of `del`, `value` is always `null`. Watch for application updates. The `operation` may be `set` or `del`. In the case of `del`, `value` is always `null`.
### `for await (const [key, value] of pear.preferences.list())` ### `for await (const [key, value] of Pear.preferences.list())`
Iterate through all available application preferences. Iterate through all available application preferences.
### `const success = await pear.preferences.set(key, value)` ### `const success = await Pear.preferences.set(key, value)`
Set a preference. The promise resolves to a boolean indicating success when the operation is complete. Set a preference. The promise resolves to a boolean indicating success when the operation is complete.
### `const value = await pear.preferences.get(key)` ### `const value = await Pear.preferences.get(key)`
Get a preference. The promise resolves with the value. Get a preference. The promise resolves with the value.
### `const success = await pear.preferences.del(key)` ### `const success = await Pear.preferences.del(key)`
Delete a preference. The promise resolves to a boolean indicating success when the operation is complete. Delete a preference. The promise resolves to a boolean indicating success when the operation is complete.
```js ```js
import { preferences } from 'pear' const { preferences } = Pear
async function logPrefUpdates () { async function logPrefUpdates () {
for await (const [ operation, key, value ] of preferences()) console.table({ update: { operation, key, value }}) for await (const [ operation, key, value ] of preferences()) console.table({ update: { operation, key, value }})
@@ -263,11 +257,11 @@ async function logPrefUpdates () {
logPrefUpdates().catch(console.error) logPrefUpdates().catch(console.error)
``` ```
## `pear.media <Object>` ## `Pear.media <Object>`
Media interface Media interface
### `const status = await pear.media.status.microphone()` ### `const status = await Pear.media.status.microphone()`
Resolves to: `<String>`. Resolves to: `<String>`.
@@ -275,7 +269,7 @@ If access to the microphone is available, resolved value will be `'granted'`.
Any other string indicates lack of permission. Possible values are `'granted'`, `'not-determined'`, `'denied'`, `'restricted'`, `'unknown'`. Any other string indicates lack of permission. Possible values are `'granted'`, `'not-determined'`, `'denied'`, `'restricted'`, `'unknown'`.
### `const status = await pear.media.status.camera()` ### `const status = await Pear.media.status.camera()`
Resolves to: `<String>`. Resolves to: `<String>`.
@@ -283,7 +277,7 @@ If access to the camera is available, resolved value will be `'granted'`.
Any other string indicates lack of permission. Possible values are `'granted'`, `'not-determined'`, `'denied'`, `'restricted'`, `'unknown'`. Any other string indicates lack of permission. Possible values are `'granted'`, `'not-determined'`, `'denied'`, `'restricted'`, `'unknown'`.
### `const status = await pear.media.status.screen()` ### `const status = await Pear.media.status.screen()`
Resolves to: `<String>` Resolves to: `<String>`
@@ -291,25 +285,25 @@ If access to the screen is available, resolved value will be `'granted'`.
Any other string indicates lack of permission. Possible values are `'granted'`, `'not-determined'`, `'denied'`, `'restricted'`, `'unknown'`. Any other string indicates lack of permission. Possible values are `'granted'`, `'not-determined'`, `'denied'`, `'restricted'`, `'unknown'`.
### `const success = await pear.media.access.microphone()` ### `const success = await Pear.media.access.microphone()`
Resolves to: `<Boolean>` Resolves to: `<Boolean>`
Request access to the microphone. Resolves to `true` if permission is granted. Request access to the microphone. Resolves to `true` if permission is granted.
### `const success = await pear.media.access.camera()` ### `const success = await Pear.media.access.camera()`
Resolves to: `<Boolean>` Resolves to: `<Boolean>`
Request access to the camera. Resolves to `true` if permission is granted. Request access to the camera. Resolves to `true` if permission is granted.
### `const success = await pear.media.access.screen()` ### `const success = await Pear.media.access.screen()`
Resolves to: `<Boolean>` Resolves to: `<Boolean>`
Request access to screen sharing. Resolves to `true` if permission is granted. Request access to screen sharing. Resolves to `true` if permission is granted.
### `const sources = await pear.media.desktopSources(options <Object>)` ### `const sources = await Pear.media.desktopSources(options <Object>)`
Captures available desktop sources. Resolves to an array of objects with shape `{ id <String>, name <String>, thumbnail <NativeImage>, display_id <String>, appIcon <NativeImage> }`. The `id` is the window or screen identifier. The `name` is the window title or `'Screen <index>'` in multiscreen scenarios or else `Entire Screen`. The `display_id` identifies the screen. The thumbnail is a scaled down screen capture of the window/screen. Captures available desktop sources. Resolves to an array of objects with shape `{ id <String>, name <String>, thumbnail <NativeImage>, display_id <String>, appIcon <NativeImage> }`. The `id` is the window or screen identifier. The `name` is the window title or `'Screen <index>'` in multiscreen scenarios or else `Entire Screen`. The `display_id` identifies the screen. The thumbnail is a scaled down screen capture of the window/screen.
@@ -329,7 +323,7 @@ Captures available desktop sources. Resolves to an array of objects with shape `
* https://www.electronjs.org/docs/latest/api/structures/desktop-capturer-source * https://www.electronjs.org/docs/latest/api/structures/desktop-capturer-source
* [`<NativeImage>`](https://www.electronjs.org/docs/latest/api/native-image) * [`<NativeImage>`](https://www.electronjs.org/docs/latest/api/native-image)
### `pear.versions <Object>` ### `Pear.versions <Object>`
Versions object. Pear versions are objects with the shape `{ fork <Integer>, length <Integer>, key <Buffer> }`. Versions object. Pear versions are objects with the shape `{ fork <Integer>, length <Integer>, key <Buffer> }`.
@@ -337,20 +331,20 @@ The `key` is a Buffer of the launch key. The `length` is the size of the relevan
These three properties together are a unique identifier for the entire state of both applications and the Pear platform. These three properties together are a unique identifier for the entire state of both applications and the Pear platform.
### `pear.versions.platform { fork <Integer>, length <Integer>, key <Buffer> }` ### `Pear.versions.platform { fork <Integer>, length <Integer>, key <Buffer> }`
The platform version. The platform version.
### `pear.versions.application { fork <Integer>, length <Integer>, key <Buffer> }` ### `Pear.versions.application { fork <Integer>, length <Integer>, key <Buffer> }`
The application version. The application version.
**References** **References**
* [pear.config.key](#pearconfigkey-objectnull) * [Pear.config.key](#pearconfigkey-objectnull)
### `pear.teardown(fn <Async Function|Function>)` ### `Pear.teardown(fn <Async Function|Function>)`
Register application clean-up handlers to be called when an application begins to unload. Register application clean-up handlers to be called when an application begins to unload.
@@ -360,11 +354,11 @@ Functions supplied to teardown will be executed in order of registration when
an application begins to unload. Any promise returned from each supplied function an application begins to unload. Any promise returned from each supplied function
will be waited upon until resolution before calling the next teardown handler. will be waited upon until resolution before calling the next teardown handler.
### `pear.restart()` ### `Pear.restart()`
Restart the application. Restart the application.
### `pear.updates(listener <Async Function|Function>)` ### `Pear.updates(listener <Async Function|Function>)`
The `listener` function is called for every incoming update with an `update` object of the form: The `listener` function is called for every incoming update with an `update` object of the form:
@@ -382,7 +376,9 @@ The `listener` function is called for every incoming update with an `update` obj
* `diff` is an array of file paths from the application root (drive keys) that were updated * `diff` is an array of file paths from the application root (drive keys) that were updated
### `const win = new pear.Window(entry <String>, options <Object>)` ### `const win = new Pear.Window(entry <String>, options <Object>)`
Desktop Applications only.
Create a new `Window` instance. Create a new `Window` instance.
@@ -514,11 +510,11 @@ Send arguments to the window. They will be serialized with `JSON.stringify`.
Resolves to: `<String>` Resolves to: `<String>`
Correlates to the `id` property of objects in the array returned from [pear.media.desktopSources](#const-sources---await-appmediadesktopsources-options). Correlates to the `id` property of objects in the array returned from [Pear.media.desktopSources](#const-sources---await-appmediadesktopsources-options).
**References** **References**
* [pear.media.desktopSources](#const-sources--await-appmediadesktopsourcesoptions-object) * [Pear.media.desktopSources](#const-sources--await-appmediadesktopsourcesoptions-object)
* https://www.electronjs.org/docs/latest/api/browser-window#wingetmediasourceid * https://www.electronjs.org/docs/latest/api/browser-window#wingetmediasourceid
### `const dimensions = await win.dimensions()` ### `const dimensions = await win.dimensions()`
@@ -538,8 +534,7 @@ If the window is closed this will resolve to `null`.
### `await win.dimensions(options <Object>)` ### `await win.dimensions(options <Object>)`
```js ```js
import { Window } from 'pear' const win = new Pear.Window('./some.html', {
const win = new Window('./some.html', {
x: 10, x: 10,
y: 450, y: 450,
width: 300, width: 300,
@@ -605,7 +600,9 @@ Resolves to: `<Boolean>`
Whether the window is closed. Whether the window is closed.
### `const view = new pear.View(options <Object>)` ### `const view = new Pear.View(options <Object>)`
Desktop Applications only.
Create a new `View` instance. Views provide isolated content views. Frameless, chromeless windows that can be embedded inside other windows and views. Create a new `View` instance. Views provide isolated content views. Frameless, chromeless windows that can be embedded inside other windows and views.
@@ -685,11 +682,11 @@ Send arguments to the view. They will be serialized with `JSON.stringify`.
Resolves to: `<String>` Resolves to: `<String>`
Supplies the `id` property of objects in the array returned from [pear.media.desktopSources](#const-sources---await-appmediadesktopsources-options). Supplies the `id` property of objects in the array returned from [Pear.media.desktopSources](#const-sources---await-appmediadesktopsources-options).
**References** **References**
* [pear.media.desktopSources](#const-sources---await-appmediadesktopsources-options) * [Pear.media.desktopSources](#const-sources---await-appmediadesktopsources-options)
* https://www.electronjs.org/docs/latest/api/browser-window#wingetmediasourceid * https://www.electronjs.org/docs/latest/api/browser-window#wingetmediasourceid
### `const dimensions = await view.dimensions()` ### `const dimensions = await view.dimensions()`
@@ -709,8 +706,7 @@ If the Window is closed this will resolve to `null`.
### `await view.dimensions(options <Object>)` ### `await view.dimensions(options <Object>)`
```js ```js
import { View } from 'pear' const view = new Pear.View('./some.html', {
const view = new View('./some.html', {
x: 10, x: 10,
y: 450, y: 450,
width: 300, width: 300,
@@ -754,7 +750,7 @@ Resolves to: `<Boolean>`
Whether the view is closed. Whether the view is closed.
### `const { self } = pear.Window` `const { self } = pear.View` ### `const { self } = Pear.Window` `const { self } = Pear.View`
### `const success = await self.focus()` ### `const success = await self.focus()`
@@ -839,7 +835,7 @@ Resolves to: `<Boolean>`
Whether the current window is minmized. Throws a `TypeError` if `self` is a view. Whether the current window is minmized. Throws a `TypeError` if `self` is a view.
### `const { parent } = pear.Window` `const { parent } = pear.View` ### `const { parent } = Pear.Window` `const { parent } = Pear.View`
### `parent.on[ce]('message', (...args) => { })` ### `parent.on[ce]('message', (...args) => { })`
### `for await (const [ ...args ] of parent)` ### `for await (const [ ...args ] of parent)`
@@ -945,7 +941,7 @@ The [`window.open`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open
In browsers, `window.open` opens a new browser window. The opened window belongs to the same browser from which `window.open` is called. In browsers, `window.open` opens a new browser window. The opened window belongs to the same browser from which `window.open` is called.
In Pear, `window.open` loads the URL in the **default system browser**. It does *not* create a new application window (use `pear.Window` to create application windows). In Pear, `window.open` loads the URL in the **default system browser**. It does *not* create a new application window (use `Pear.Window` to create application windows).
Therefore Pear's `window.open` only supports a single url argument. The `target` and `windowFeatures` parameters that browsers support are discarded. Therefore Pear's `window.open` only supports a single url argument. The `target` and `windowFeatures` parameters that browsers support are discarded.
@@ -958,7 +954,3 @@ Like browsers, there is support for native EcmaScript Modules (ESM). A JavaScrip
Use `<script type="module" src="path/to/my-file.js">` to load a JavaScript Module. Use `<script type="module" src="path/to/my-file.js">` to load a JavaScript Module.
Use `<script src="path/to/my-file.js">` to load a JavaScript Script. Use `<script src="path/to/my-file.js">` to load a JavaScript Script.
## Development Global
The Pear API is exposed as `global.pear` for the explicit purpose of easy API experimentation in the Devtools Console. It is *only* exposed globally in development mode. Any module that uses the Pear API must be sure to import `pear`, relying on `global.pear` will cause production breakage.