pear-mobile 0.1.0-rc → 1.0.0-rc
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 +12 -5
- package/index.js +107 -90
- package/package.json +12 -19
- package/lib/pear.bundle.js +0 -1
package/README.md
CHANGED
|
@@ -15,18 +15,25 @@ Requires `react-native-bare-kit` to be listed in project dependencies.
|
|
|
15
15
|
## Usage
|
|
16
16
|
|
|
17
17
|
```js
|
|
18
|
+
/* React Native */
|
|
18
19
|
import PearRuntime from 'pear-mobile'
|
|
19
20
|
import bundle from './worker.bundle.js'
|
|
20
21
|
import { version, upgrade } from './package.json'
|
|
21
22
|
|
|
22
|
-
const runtime = new PearRuntime(
|
|
23
|
+
const runtime = new PearRuntime()
|
|
24
|
+
const IPC = runtime.run('/worker.bundle', bundle, [runtime.dir])
|
|
25
|
+
|
|
26
|
+
/* Bare Worklet */
|
|
27
|
+
const PearRuntime = require('pear-runtime')
|
|
28
|
+
const { version, upgrade } = require('./package.json')
|
|
29
|
+
|
|
30
|
+
const dir = Bare.argv[0]
|
|
31
|
+
|
|
32
|
+
const runtime = new PearRuntime({version, upgrade, dir})
|
|
23
33
|
runtime.on('updated', () => {
|
|
24
34
|
runtime.applyUpdate()
|
|
35
|
+
conosle.log('restart for update')
|
|
25
36
|
})
|
|
26
|
-
|
|
27
|
-
const appStorage = runtime.storage
|
|
28
|
-
|
|
29
|
-
const IPC = runtime.run('/worker.bundle', bundle, [appStorage])
|
|
30
37
|
```
|
|
31
38
|
|
|
32
39
|
## API
|
package/index.js
CHANGED
|
@@ -1,109 +1,126 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.
|
|
1
|
+
/* global BareKit */
|
|
2
|
+
|
|
3
|
+
const Hyperswarm = require('hyperswarm')
|
|
4
|
+
const Hyperdrive = require('hyperdrive')
|
|
5
|
+
const Corestore = require('corestore')
|
|
6
|
+
const path = require('bare-path')
|
|
7
|
+
const fs = require('bare-fs')
|
|
8
|
+
const fsx = require('fs-native-extensions')
|
|
9
|
+
const ReadyResource = require('ready-resource')
|
|
10
|
+
const plink = require('pear-link')
|
|
11
|
+
const hid = require('hypercore-id-encoding')
|
|
12
|
+
const Localdrive = require('localdrive')
|
|
13
|
+
const { isIOS } = require('which-runtime')
|
|
14
|
+
|
|
15
|
+
module.exports = class PearRuntime extends ReadyResource {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super()
|
|
18
|
+
if (!config.dir) throw new Error('PearRuntime needs "dir" to /Documents Sandbox')
|
|
19
|
+
const { drive: upgrade } = plink.parse(config.upgrade)
|
|
20
|
+
this.dir = config.dir
|
|
21
|
+
this.version = config.version || 0
|
|
22
|
+
this.app = path.join(this.dir, 'pear-runtime/upgrade', isIOS ? 'runtime.ios.bundle' : 'runtime.android.bundle')
|
|
23
|
+
this.name = isIOS ? 'runtime.ios.bundle' : 'runtime.android.bundle'
|
|
24
|
+
this.key = hid.decode(upgrade.key)
|
|
25
|
+
this.length = upgrade.length || 0
|
|
26
|
+
this.fork = upgrade.fork || 0
|
|
27
|
+
this.link = plink.serialize({ drive: { fork: this.fork, length: this.length, key: this.key }})
|
|
28
|
+
this.store = config.store || new Corestore(path.join(this.dir, 'pear-runtime/corestore'))
|
|
29
|
+
this.drive = new Hyperdrive(this.store, this.key)
|
|
30
|
+
this.swarm = config.swarm || null
|
|
31
|
+
this.next = null
|
|
32
|
+
this.checkout = null
|
|
33
|
+
|
|
34
|
+
this.updating = false
|
|
35
|
+
this.updated = false
|
|
36
|
+
|
|
37
|
+
this.ready().catch(noop)
|
|
22
38
|
}
|
|
23
39
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
this.
|
|
27
|
-
|
|
40
|
+
async _open() {
|
|
41
|
+
await this.drive.ready()
|
|
42
|
+
await fs.rm(path.join(this.dir, 'pear-runtime/next'), {
|
|
43
|
+
recursive: true,
|
|
44
|
+
force: true
|
|
45
|
+
})
|
|
46
|
+
await fs.mkdir(path.join(this.dir, 'pear-runtime/next'), { recursive: true, force: true })
|
|
47
|
+
if (!this.swarm) {
|
|
48
|
+
const keyPair = await this.store.createKeyPair('pear-container')
|
|
49
|
+
this.swarm = new Hyperswarm({ keyPair })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.swarm.on('connection', (connection) => this.store.replicate(connection))
|
|
53
|
+
this.swarm.join(this.drive.core.discoveryKey, { client: true, server: false })
|
|
54
|
+
|
|
55
|
+
this._updateBackground()
|
|
56
|
+
this.drive.core.on('append', () => this._updateBackground())
|
|
28
57
|
}
|
|
29
58
|
|
|
30
|
-
async
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
await
|
|
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
|
-
})
|
|
59
|
+
async _close() {
|
|
60
|
+
await this.drive.close()
|
|
61
|
+
if (this.checkout) await this.checkout.close()
|
|
62
|
+
await this.store.destroy()
|
|
63
|
+
await this.swarm.destroy()
|
|
56
64
|
}
|
|
57
65
|
|
|
58
|
-
async applyUpdate(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
async applyUpdate() {
|
|
67
|
+
// we apply the update the same way bc react-native will always try to boot (e.g) upgrade/runtime.ios.bundle first
|
|
68
|
+
if (!this.updated || this.applied || !this.dir) return
|
|
69
|
+
this.applied = true
|
|
70
|
+
if (!await fs.exists(this.app)) {
|
|
71
|
+
await fs.mkdir(path.join(this.dir, 'pear-runtime/upgrade'), { recursive: true, force: true })
|
|
72
|
+
await fs.writeFile(this.app, '')
|
|
73
|
+
}
|
|
64
74
|
|
|
65
|
-
|
|
75
|
+
await fsx.swap(path.join(this.next, this.name), this.app)
|
|
76
|
+
await fs.promises.rm(this.next, { recursive: true, force: true })
|
|
66
77
|
}
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
on(event, callback) {
|
|
71
|
-
if (!this._listeners[event]) this._listeners[event] = []
|
|
72
|
-
this._listeners[event].push(callback)
|
|
73
|
-
return this
|
|
79
|
+
_updateBackground() {
|
|
80
|
+
this._update().catch(noop)
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
async _update() {
|
|
84
|
+
if (this.updating) return
|
|
85
|
+
this.updating = true
|
|
86
|
+
|
|
87
|
+
const length = this.drive.core.length
|
|
88
|
+
const id = length + '.' + this.drive.core.fork
|
|
89
|
+
const next = path.join(this.dir, 'pear-runtime/next', id)
|
|
90
|
+
const co = this.drive.checkout(length)
|
|
91
|
+
|
|
92
|
+
this.checkout = co
|
|
93
|
+
|
|
94
|
+
const manifest = await co.get('/package.json')
|
|
95
|
+
const version = manifest && JSON.parse(manifest).version
|
|
96
|
+
if (!manifest || version === this.version) {
|
|
97
|
+
this.updating = false
|
|
98
|
+
this.checkout = null
|
|
99
|
+
await co.close()
|
|
100
|
+
return
|
|
83
101
|
}
|
|
84
|
-
return this
|
|
85
|
-
}
|
|
86
102
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
const local = new Localdrive(next)
|
|
104
|
+
|
|
105
|
+
this.emit('updating')
|
|
106
|
+
|
|
107
|
+
for await (const data of co.mirror(local)) {
|
|
108
|
+
this.emit('updating-delta', data)
|
|
91
109
|
}
|
|
92
|
-
return this.on(event, wrap)
|
|
93
|
-
}
|
|
94
110
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
111
|
+
await co.close()
|
|
112
|
+
await local.close()
|
|
113
|
+
|
|
114
|
+
this.checkout = null
|
|
115
|
+
this.length = length
|
|
116
|
+
this.next = next
|
|
117
|
+
|
|
118
|
+
this.updating = false
|
|
119
|
+
this.updated = true
|
|
120
|
+
this.emit('updated', version)
|
|
101
121
|
|
|
102
|
-
|
|
103
|
-
const worklet = new Worklet()
|
|
104
|
-
worklet.start(filename, bundle, argv)
|
|
105
|
-
return worklet.IPC
|
|
122
|
+
if (this.drive.core.length > length) this._updateBackground()
|
|
106
123
|
}
|
|
107
124
|
}
|
|
108
125
|
|
|
109
|
-
function noop() {}
|
|
126
|
+
function noop() {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pear-mobile",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0-rc",
|
|
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
|
-
"
|
|
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,27 +35,21 @@
|
|
|
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"
|
|
38
|
+
"prettier-config-holepunch": "^2.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"bare-path": "^3.0.0",
|
|
42
|
+
"corestore": "^7.8.0",
|
|
43
|
+
"fs-native-extensions": "^1.4.5",
|
|
44
|
+
"hypercore-id-encoding": "^1.3.0",
|
|
40
45
|
"hyperdrive": "^13.2.1",
|
|
41
46
|
"hyperswarm": "^4.16.0",
|
|
42
47
|
"localdrive": "^2.2.0",
|
|
43
48
|
"pear-link": "^4.2.1",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"bare-pack": "^2.0.0",
|
|
47
|
-
"bare-path": "^3.0.0",
|
|
48
|
-
"corestore": "^7.8.0",
|
|
49
|
-
"hypercore-id-encoding": "^1.3.0",
|
|
50
|
-
"ready-resource": "^1.2.0"
|
|
51
|
-
},
|
|
52
|
-
"dependencies": {
|
|
53
|
-
"b4a": "^1.7.4",
|
|
54
|
-
"bare-rpc": "^1.1.0",
|
|
55
|
-
"react-native-fs": "^2.20.0"
|
|
49
|
+
"ready-resource": "^1.2.0",
|
|
50
|
+
"which-runtime": "^1.3.2"
|
|
56
51
|
},
|
|
57
52
|
"peerDependencies": {
|
|
58
|
-
"react-native-bare-kit": "*"
|
|
59
|
-
"@react-native-async-storage/async-storage": "*",
|
|
60
|
-
"react-native": "*"
|
|
53
|
+
"react-native-bare-kit": "*"
|
|
61
54
|
}
|
|
62
55
|
}
|