pear-mobile 0.1.1-rc → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,68 +6,103 @@ Embeddable Pear runtime for mobile applications. Provides storage path and bare
6
6
  npm install pear-mobile
7
7
  ```
8
8
 
9
- ```sh
10
- npm install react-native-bare-kit --save
11
- ```
9
+ This module integrates Pear into React-Native-based Mobile applications.
10
+
11
+ See [pear-runtime](https://github.com/holepunchto/pear-runtime) for Pear's embeddable runtime module for Desktop Devices.
12
12
 
13
- Requires `react-native-bare-kit` to be listed in project dependencies.
13
+ ## MVP - EXPERIMENTAL
14
+
15
+ This boilerplate is MVP and Experimental.
14
16
 
15
17
  ## Usage
16
18
 
17
19
  ```js
18
- import PearRuntime from 'pear-mobile'
19
- import bundle from './worker.bundle.js'
20
- import { version, upgrade } from './package.json'
20
+ const PearRuntime = require('pear-mobile')
21
+ const { version, upgrade } = require('./package.json')
22
+
23
+ const dir = Bare.argv[0] // pass the /Documents storage dir
21
24
 
22
- const runtime = new PearRuntime({ version, upgrade })
23
- runtime.on('updated', () => {
24
- runtime.applyUpdate()
25
+ const runtime = new PearRuntime({ version, upgrade, dir })
26
+ runtime.updater.on('updated', async () => {
27
+ await runtime.updater.applyUpdate()
28
+ conosle.log('restart for update')
25
29
  })
30
+ ```
31
+
32
+ ## Quick Starts
26
33
 
27
- const appStorage = runtime.storage
34
+ ### Expo
28
35
 
29
- const IPC = runtime.run('/worker.bundle', bundle, [appStorage])
36
+ ```sh
37
+ git clone https://github.com/holepunchto/hello-pear-react-native
30
38
  ```
31
39
 
40
+ For end-to-end instructions from building to deploying with [Pear](https://docs.pears.com) see [hello-pear-react-native](https://github.com/holepunchto/hello-pear-react-native) `README.md`.
41
+
42
+ ## Features
43
+
44
+ - Peer-to-Peer Over-the-Air (P2P OTA) updates (via [pear-runtime-updater](https://www.github.com/holepunchto/pear-runtime-updater))
45
+ - Application storage management
46
+
32
47
  ## API
33
48
 
34
- #### `const runtime = new PearRuntime(...)`
49
+ #### `const pear = new PearRuntime(opts)`
50
+
51
+ Create a runtime. `opts` may include:
52
+
53
+ - **`dir`** (required) Directory to store data (e.g. app data dir).
54
+ - **`upgrade`** – (required) Pear link for OTA updates (e.g. from `package.json` `upgrade` field).
55
+ - **`version`** – Current app version (e.g. from `package.json`); used for update checks.
56
+ - **`app`** – Path to the native boot bundle override; required for `applyUpdate()` to swap in the new build. Defaults to `path/to/Documents/pear-runtime/upgrades`
57
+ - **`updates`** – Set to `false` to disable P2P OTA updates.
58
+ - **`storage`** – Saves the app storage path.
35
59
 
36
- Create a runtime.
60
+ #### `pear.storage`
37
61
 
38
- #### `runtime.storage`
62
+ Suggested storage folder for app storage.
39
63
 
40
- Absolute path to the runtime app storage directory.
64
+ #### `pear.updater`
41
65
 
42
- #### `runtime.on(event, callback)`
66
+ Instance of [pear-runtime-updater](https://www.github.com/holepunchto/pear-runtime-updater)
43
67
 
44
- Subscribe to an event. Returns `runtime` for chaining.
68
+ #### `await updater.ready()`
45
69
 
46
- #### `runtime.off(event, callback?)`
70
+ Awaits the open of the updater (p2p connections, drive open ...)
47
71
 
48
- Unsubscribe: remove `callback` for `event`, or remove all listeners for `event` if `callback` is omitted. Returns `runtime`.
72
+ #### `await pear.close()`
49
73
 
50
- #### `runtime.once(event, callback)`
74
+ Shut it down. You should do this when closing your app for best performance.
51
75
 
52
- Subscribe to an event once; listener is removed after the first emit. Returns `runtime`.
76
+ ## Making updates
53
77
 
54
- #### `IPC = runtime.run(filename, bundle, argv)`
78
+ VERY EXPERIMENTAL, MOST DEFINITELY WILL CHANGE.
55
79
 
56
- Start a bare worker (worklet). Returns an IPC duplex stream. `filename` is a virtual path, `bundle` is the worklet bundle, `argv` is an array of string arguments.
80
+ Update listening and apply logic lives in [pear-runtime-updater](https://www.github.com/holepunchto/pear-runtime-updater).
57
81
 
58
- `Bare.argv` in worker to access `argv`.
82
+ First allocate a pear link if you haven't using [`pear`](https://github.com/holepunchto/pear):
83
+
84
+ ```sh
85
+ pear touch
86
+ ```
59
87
 
60
- #### `runtime.ready()`
88
+ Store this link in the `package.json` `upgrade` field of a project.
61
89
 
62
- Returns a Promise. No-op on mobile; for API compatibility.
90
+ bundle your JS frontend. Take the distributable (e.g react-native bundle and assets) produced and make a deployment folder with the following structure:
63
91
 
64
- #### `runtime.close()`
92
+ ```
93
+ /package.json
94
+ /by-arch
95
+ /[...platform-arch]
96
+ /app
97
+ ```
65
98
 
66
- Returns a Promise. No-op on mobile; for API compatibility.
99
+ Now go to this folder and stage this onto the link with `pear stage`
67
100
 
68
- #### `runtime.applyUpdate()`
101
+ ```sh
102
+ pear stage {link-from-touch}
103
+ ```
69
104
 
70
- Returns a Promise. On mobile this is not supported and only logs a warning; for API compatibility.
105
+ Now seed it. Any build out there on a lower version will trigger the update flow.
71
106
 
72
107
  ## LICENSE
73
108
 
package/index.js CHANGED
@@ -1,109 +1,30 @@
1
- const { Worklet } = require('react-native-bare-kit') // NEED TO INSTALL IN ROOT PRJECT (version match)
2
- const bundle = require('./lib/pear.bundle.js')
3
- const RPC = require('bare-rpc')
4
- const RNFS = require('react-native-fs')
5
- const AsyncStorage = require('@react-native-async-storage/async-storage') // NEED TO INSTALL IN ROOT PRJECT (version match)
6
- const { DevSettings } = require('react-native') // NEED TO INSTALL IN ROOT PRJECT (version match)
7
- const b4a = require('b4a')
8
-
9
- module.exports = class PearRuntime {
10
- constructor(config = {}) {
11
- if (!config.upgrade) throw new Error('upgrade link required')
12
- this.config = {
13
- dir: `${RNFS.DocumentDirectoryPath}/pear-runtime`,
14
- isDev: __DEV__,
15
- ...config
1
+ const PearRuntimeUpdater = require('pear-runtime-updater')
2
+ const ReadyResouce = require('ready-resource')
3
+ const path = require('bare-path')
4
+ const fs = require('bare-fs')
5
+ const dir = require('bare-storage')
6
+
7
+ module.exports = class PearRuntime extends ReadyResouce {
8
+ constructor(opts = {}) {
9
+ super()
10
+ if (!opts.dir) opts.dir = dir.persistent()
11
+ const appPath = opts.app || path.join(opts.dir, 'pear-runtime', 'upgrade')
12
+ if (!fs.existsSync(appPath)) fs.mkdirSync(appPath, { recursive: true, force: true })
13
+ if (fs.existsSync(path.join(appPath, 'package.json'))) {
14
+ const manifest = fs.readFileSync(path.join(appPath, 'package.json'))
15
+ opts.version = JSON.parse(manifest).version
16
16
  }
17
+ opts = { app: appPath, ...opts }
18
+ this.storage = opts.storage || path.join(this.dir, 'app-storage')
17
19
 
18
- this._listeners = Object.create(null)
19
- this._calledReady = null
20
-
21
- this.IPCPromise = this.ready().catch(noop)
22
- }
23
-
24
- ready() {
25
- if (this._calledReady) return this._calledReady
26
- this._calledReady = this._open()
27
- return this._calledReady
20
+ this.updater = new PearRuntimeUpdater(opts)
28
21
  }
29
22
 
30
23
  async _open() {
31
- const runtimeDir = `${RNFS.DocumentDirectoryPath}/pear-runtime`
32
- const storageDir = `${runtimeDir}/storage`
33
-
34
- await RNFS.mkdir(runtimeDir)
35
- await RNFS.mkdir(storageDir)
36
-
37
- const argv = [JSON.stringify(this.config)]
38
- const worklet = new Worklet()
39
- worklet.start('/pear.bundle', bundle, argv)
40
-
41
- return new RPC(worklet.IPC, async (req) => {
42
- if (req.command === 0) {
43
- const version = b4a.toString(req.data)
44
- console.log('received version form pearend:', version)
45
- this.emit('updated')
46
- }
47
- if (req.command === 1){
48
- const updateData = b4a.toString(req.data)
49
- console.log('[Update Diff]', updateData)
50
- }
51
- if (req.command === 2){
52
- const logString = b4a.toString(req.data)
53
- console.log('[pear-runtime]:', logString)
54
- }
55
- })
56
- }
57
-
58
- async applyUpdate(version) {
59
- await AsyncStorage.multiSet([
60
- ['updatePending', 'true'],
61
- ['updateConfirmed', 'false'],
62
- ['runtimeVersion', String(version ?? this.version)]
63
- ])
64
-
65
- DevSettings.reload()
66
- }
67
-
68
- async close() {}
69
-
70
- on(event, callback) {
71
- if (!this._listeners[event]) this._listeners[event] = []
72
- this._listeners[event].push(callback)
73
- return this
74
- }
75
-
76
- off(event, callback) {
77
- if (!this._listeners[event]) return this
78
- if (callback) {
79
- this._listeners[event] =
80
- this._listeners[event].filter(fn => fn !== callback)
81
- } else {
82
- this._listeners[event] = []
83
- }
84
- return this
24
+ await this.updater.ready()
85
25
  }
86
26
 
87
- once(event, fn) {
88
- const wrap = (...args) => {
89
- this.off(event, wrap)
90
- fn(...args)
91
- }
92
- return this.on(event, wrap)
93
- }
94
-
95
- emit(event, ...args) {
96
- const list = this._listeners[event]
97
- if (!list) return this
98
- for (const fn of list) fn(...args)
99
- return this
100
- }
101
-
102
- run(filename, bundle, argv) {
103
- const worklet = new Worklet()
104
- worklet.start(filename, bundle, argv)
105
- return worklet.IPC
27
+ async _close() {
28
+ await this.updater.close()
106
29
  }
107
30
  }
108
-
109
- function noop() {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pear-mobile",
3
- "version": "0.1.1-rc",
3
+ "version": "1.0.0",
4
4
  "description": "Embeddable Pear runtime for mobile applications",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -14,10 +14,9 @@
14
14
  "package.json",
15
15
  "index.js",
16
16
  "index.d.ts",
17
- "lib/pear.bundle.js"
17
+ "index.rn.js"
18
18
  ],
19
19
  "scripts": {
20
- "build": "npx bare-pack --host ios --host android --linked --out ./lib/pear.bundle.js ./lib/pear.js",
21
20
  "format": "prettier . --write",
22
21
  "test": "prettier . --check && lunte && brittle-bare test/index.js",
23
22
  "lint": "lunte"
@@ -36,25 +35,13 @@
36
35
  "brittle": "^3.19.0",
37
36
  "lunte": "^1.2.0",
38
37
  "prettier": "^3.6.2",
39
- "prettier-config-holepunch": "^2.0.0",
40
- "bare-pack": "^2.0.0"
38
+ "prettier-config-holepunch": "^2.0.0"
41
39
  },
42
40
  "dependencies": {
43
- "b4a": "^1.7.4",
44
- "bare-rpc": "^1.1.0",
45
- "react-native-fs": "^2.20.0",
46
- "hyperdrive": "^13.2.1",
47
- "hyperswarm": "^4.16.0",
48
- "localdrive": "^2.2.0",
49
- "pear-link": "^4.2.1",
41
+ "bare-fs": "^4.5.4",
50
42
  "bare-path": "^3.0.0",
51
- "corestore": "^7.8.0",
52
- "hypercore-id-encoding": "^1.3.0",
43
+ "bare-storage": "^1.0.1",
44
+ "pear-runtime-updater": "^0.0.13",
53
45
  "ready-resource": "^1.2.0"
54
- },
55
- "peerDependencies": {
56
- "react-native-bare-kit": "*",
57
- "@react-native-async-storage/async-storage": "*",
58
- "react-native": "*"
59
46
  }
60
47
  }