pear-electron 0.0.1

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/gui/index.js ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict'
2
+ module.exports = process.type === 'renderer' ? require('./preload') : require('./gui')
package/gui/preload.js ADDED
@@ -0,0 +1,366 @@
1
+ /* eslint-env browser */
2
+ 'use strict'
3
+ const streamx = require('streamx')
4
+ const { EventEmitter } = require('events')
5
+ const Iambus = require('iambus')
6
+ const electron = require('electron')
7
+ const noop = () => {}
8
+ class Worker extends require('pear-api/worker') {
9
+ #ipc = null
10
+ constructor ({ ref = noop, unref = noop, ipc } = {}) {
11
+ super({ ref, unref })
12
+ this.#ipc = ipc
13
+ }
14
+
15
+ run (link, args = []) { return this.#ipc.workerRun(link, args) }
16
+ }
17
+
18
+ module.exports = class PearGUI {
19
+ constructor ({ API, state }) {
20
+ const id = this.id = electron.ipcRenderer.sendSync('id')
21
+
22
+ this.ipc = new IPC()
23
+ electron.ipcRenderer.on('ipc', (e, data) => {
24
+ this.ipc.stream.push(Buffer.from(data))
25
+ })
26
+
27
+ const teardown = async (fn) => {
28
+ if (state.isDecal) return
29
+ const action = await this.ipc.unloading({ id }) // only resolves when unloading occurs
30
+ await fn()
31
+ await this.ipc.completeUnload({ id, action })
32
+ if (action.type === 'reload') location.reload()
33
+ else if (action.type === 'nav') location.href = action.url
34
+ }
35
+
36
+ API = class extends API {
37
+ static UI = Symbol('ui')
38
+ constructor (ipc, state) {
39
+ const worker = new Worker({ ipc })
40
+ super(ipc, state, { teardown, worker })
41
+ this[Symbol.for('pear.ipc')] = ipc
42
+ const media = {
43
+ status: {
44
+ microphone: () => ipc.getMediaAccessStatus({ id, media: 'microphone' }),
45
+ camera: () => ipc.getMediaAccessStatus({ id, media: 'camera' }),
46
+ screen: () => ipc.getMediaAccessStatus({ id, media: 'screen' })
47
+ },
48
+ access: {
49
+ microphone: () => ipc.askForMediaAccess({ id, media: 'microphone' }),
50
+ camera: () => ipc.askForMediaAccess({ id, media: 'camera' }),
51
+ screen: () => ipc.askForMediaAccess({ id, media: 'screen' })
52
+ },
53
+ desktopSources: (options = {}) => ipc.desktopSources(options)
54
+ }
55
+
56
+ const kGuiCtrl = Symbol('gui:ctrl')
57
+
58
+ class Parent extends EventEmitter {
59
+ #id
60
+ constructor (id) {
61
+ super()
62
+ this.#id = id
63
+ electron.ipcRenderer.on('send', (e, ...args) => {
64
+ this.emit('message', ...args)
65
+ })
66
+ }
67
+
68
+ send (...args) { return electron.ipcRenderer.send('send-to', this.#id, ...args) }
69
+ focus (options = null) { return ipc.parent({ act: 'focus', id: this.#id, options }) }
70
+ blur () { return ipc.parent({ act: 'blur', id: this.#id }) }
71
+ show () { return ipc.parent({ act: 'show', id: this.#id }) }
72
+ hide () { return ipc.parent({ act: 'hide', id: this.#id }) }
73
+ minimize () { return ipc.parent({ act: 'minimize', id: this.#id }) }
74
+ maximize () { return ipc.parent({ act: 'maximize', id: this.#id }) }
75
+ fullscreen () { return ipc.parent({ act: 'fullscreen', id: this.#id }) }
76
+ restore () { return ipc.parent({ act: 'restore', id: this.#id }) }
77
+ dimensions (options = null) { return ipc.parent({ act: 'dimensions', id: this.#id, options }) }
78
+ isVisible () { return ipc.parent({ act: 'isVisible', id: this.#id }) }
79
+ isMinimized () { return ipc.parent({ act: 'isMinimized', id: this.#id }) }
80
+ isMaximized () { return ipc.parent({ act: 'isMaximized', id: this.#id }) }
81
+ isFullscreen () { return ipc.parent({ act: 'isFullscreen', id: this.#id }) }
82
+ isClosed () { return ipc.parent({ act: 'isClosed', id: this.#id }) }
83
+ }
84
+
85
+ class Self {
86
+ constructor (id) { this.id = id }
87
+ focus (options = null) { return ipc.focus({ id: this.id, options }) }
88
+ blur () { return ipc.blur({ id: this.id }) }
89
+ show () { return ipc.show({ id: this.id }) }
90
+ hide () { return ipc.hide({ id: this.id }) }
91
+ minimize () { return ipc.minimize({ id: this.id }) }
92
+ maximize () { return ipc.maximize({ id: this.id }) }
93
+ fullscreen () { return ipc.fullscreen({ id: this.id }) }
94
+ restore () { return ipc.restore({ id: this.id }) }
95
+ close () { return ipc.close({ id: this.id }) }
96
+ dimensions (options = null) { return ipc.dimensions({ id: this.id, options }) }
97
+ isVisible () { return ipc.isVisible({ id: this.id }) }
98
+ isMinimized () { return ipc.isMinimized({ id: this.id }) }
99
+ isMaximized () { return ipc.isMaximized({ id: this.id }) }
100
+ isFullscreen () { return ipc.isFullscreen({ id: this.id }) }
101
+ }
102
+
103
+ class GuiCtrl extends EventEmitter {
104
+ #listener = null
105
+
106
+ static get parent () {
107
+ Object.defineProperty(this, 'parent', {
108
+ value: new Parent(electron.ipcRenderer.sendSync('parentId'))
109
+ })
110
+ return this.parent
111
+ }
112
+
113
+ static get self () {
114
+ Object.defineProperty(this, 'self', {
115
+ value: new Self(electron.ipcRenderer.sendSync('id'))
116
+ })
117
+ return this.self
118
+ }
119
+
120
+ constructor (entry, at, options = at) {
121
+ super()
122
+ if (options === at) {
123
+ if (typeof at === 'string') options = { at }
124
+ }
125
+ if (!entry) throw new Error(`No path provided, cannot open ${this.constructor[kGuiCtrl]}`)
126
+ this.entry = entry
127
+ this.options = options
128
+ this.id = null
129
+ }
130
+
131
+ #rxtx () {
132
+ this.#listener = (e, ...args) => this.emit('message', ...args)
133
+ electron.ipcRenderer.on('send', this.#listener)
134
+ }
135
+
136
+ #unrxtx () {
137
+ if (this.#listener === null) return
138
+ electron.ipcRenderer.removeListener('send', this.#listener)
139
+ this.#listener = null
140
+ }
141
+
142
+ async open (opts) {
143
+ if (this.id === null) {
144
+ await new Promise(setImmediate) // needed for windows/views opening on app load
145
+ this.#rxtx()
146
+ this.id = await ipc.ctrl({
147
+ parentId: this.self.id,
148
+ type: this.constructor[kGuiCtrl],
149
+ entry: this.entry,
150
+ options: this.options,
151
+ state: this.state,
152
+ openOptions: opts
153
+ })
154
+ return true
155
+ }
156
+ return await ipc.open({ id: this.id })
157
+ }
158
+
159
+ async close () {
160
+ const result = await ipc.close({ id: this.id })
161
+ this.#unrxtx()
162
+ this.id = null
163
+ return result
164
+ }
165
+
166
+ show () { return ipc.show({ id: this.id }) }
167
+ hide () { return ipc.hide({ id: this.id }) }
168
+ focus (options = null) { return ipc.focus({ id: this.id, options }) }
169
+ blur () { return ipc.blur({ id: this.id }) }
170
+
171
+ dimensions (options = null) { return ipc.dimensions({ id: this.id, options }) }
172
+ minimize () {
173
+ if (this.constructor[kGuiCtrl] === 'view') throw new Error('A View cannot be minimized')
174
+ return ipc.minimize({ id: this.id })
175
+ }
176
+
177
+ maximize () {
178
+ if (this.constructor[kGuiCtrl] === 'view') throw new Error('A View cannot be maximized')
179
+ return ipc.maximize({ id: this.id })
180
+ }
181
+
182
+ fullscreen () {
183
+ if (this.constructor[kGuiCtrl] === 'view') throw new Error('A View cannot be fullscreened')
184
+ return ipc.fullscreen({ id: this.id })
185
+ }
186
+
187
+ restore () { return ipc.restore({ id: this.id }) }
188
+
189
+ isVisible () { return ipc.isVisible({ id: this.id }) }
190
+
191
+ isMinimized () {
192
+ if (this.constructor[kGuiCtrl] === 'view') throw new Error('A View cannot be minimized')
193
+ return ipc.isMinimized({ id: this.id })
194
+ }
195
+
196
+ isMaximized () {
197
+ if (this.constructor[kGuiCtrl] === 'view') throw new Error('A View cannot be maximized')
198
+ return ipc.isMaximized({ id: this.id })
199
+ }
200
+
201
+ isFullscreen () {
202
+ if (this.constructor[kGuiCtrl] === 'view') throw new Error('A View cannot be maximized')
203
+ return ipc.isFullscreen({ id: this.id })
204
+ }
205
+
206
+ isClosed () { return ipc.isClosed({ id: this.id }) }
207
+
208
+ send (...args) { return electron.ipcRenderer.send('send-to', this.id, ...args) }
209
+ }
210
+
211
+ class Window extends GuiCtrl {
212
+ static [kGuiCtrl] = 'window'
213
+ }
214
+
215
+ class View extends GuiCtrl { static [kGuiCtrl] = 'view' }
216
+
217
+ class PearElectron {
218
+ Window = Window
219
+ View = View
220
+ media = media
221
+ static DECAL = Symbol('decal')
222
+ warming () {
223
+ electron.ipcRenderer.send('warming')
224
+ const stream = new streamx.Readable()
225
+ electron.ipcRenderer.on('warming', (e, data) => { stream.push(data) })
226
+ return stream
227
+ }
228
+
229
+ constructor () {
230
+ if (state.isDecal) {
231
+ this[this.constructor.DECAL] = {
232
+ ipc,
233
+ 'hypercore-id-encoding': require('hypercore-id-encoding'),
234
+ 'pear-api/constants': require('pear-api/constants')
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ this[this.constructor.UI] = new PearElectron()
241
+ }
242
+
243
+ get media () {
244
+ console.warn('Pear.media is deprecated use require(\'pear-electron\').media')
245
+ return this[this.constructor.UI].media
246
+ }
247
+
248
+ get Window () {
249
+ console.warn('Pear.Window is deprecated use require(\'pear-electron\').Window')
250
+ return this[this.constructor.UI].Window
251
+ }
252
+
253
+ get View () {
254
+ console.warn('Pear.View is deprecated use require(\'pear-electron\').View')
255
+ return this[this.constructor.UI].View
256
+ }
257
+
258
+ exit = (code) => {
259
+ process.exitCode = code
260
+ electron.ipcRenderer.sendSync('exit', code)
261
+ }
262
+ }
263
+ this.api = new API(this.ipc, state, teardown)
264
+ }
265
+ }
266
+
267
+ class IPC {
268
+ getMediaAccessStatus (...args) { return electron.ipcRenderer.invoke('getMediaAccessStatus', ...args) }
269
+ askForMediaAccess (...args) { return electron.ipcRenderer.invoke('askForMediaAccess', ...args) }
270
+ desktopSources (...args) { return electron.ipcRenderer.invoke('desktopSources', ...args) }
271
+ chrome (...args) { return electron.ipcRenderer.invoke('chrome', ...args) }
272
+ ctrl (...args) { return electron.ipcRenderer.invoke('ctrl', ...args) }
273
+ parent (...args) { return electron.ipcRenderer.invoke('parent', ...args) }
274
+ open (...args) { return electron.ipcRenderer.invoke('open', ...args) }
275
+ close (...args) { return electron.ipcRenderer.invoke('close', ...args) }
276
+ show (...args) { return electron.ipcRenderer.invoke('show', ...args) }
277
+ hide (...args) { return electron.ipcRenderer.invoke('hide', ...args) }
278
+ minimize (...args) { return electron.ipcRenderer.invoke('minimize', ...args) }
279
+ maximize (...args) { return electron.ipcRenderer.invoke('maximize', ...args) }
280
+ setMaximizable (...args) { return electron.ipcRenderer.invoke('setMaximizable', ...args) }
281
+ setMinimizable (...args) { return electron.ipcRenderer.invoke('setMinimizable', ...args) }
282
+ fullscreen (...args) { return electron.ipcRenderer.invoke('fullscreen', ...args) }
283
+ restore (...args) { return electron.ipcRenderer.invoke('restore', ...args) }
284
+ focus (...args) { return electron.ipcRenderer.invoke('focus', ...args) }
285
+ blur (...args) { return electron.ipcRenderer.invoke('blur', ...args) }
286
+ dimensions (...args) { return electron.ipcRenderer.invoke('dimensions', ...args) }
287
+ isVisible (...args) { return electron.ipcRenderer.invoke('isVisible', ...args) }
288
+ isClosed (...args) { return electron.ipcRenderer.invoke('isClosed', ...args) }
289
+ isMinimized (...args) { return electron.ipcRenderer.invoke('isMinimized', ...args) }
290
+ isMaximized (...args) { return electron.ipcRenderer.invoke('isMaximized', ...args) }
291
+ isFullscreen (...args) { return electron.ipcRenderer.invoke('isFullscreen', ...args) }
292
+ setSize (...args) { return electron.ipcRenderer.invoke('setSize', ...args) }
293
+ permit (...args) { return electron.ipcRenderer.invoke('permit', ...args) }
294
+ unloading (...args) { return electron.ipcRenderer.invoke('unloading', ...args) }
295
+ completeUnload (...args) { return electron.ipcRenderer.invoke('completeUnload', ...args) }
296
+ attachMainView (...args) { return electron.ipcRenderer.invoke('attachMainView', ...args) }
297
+ detachMainView (...args) { return electron.ipcRenderer.invoke('detachMainView', ...args) }
298
+ afterViewLoaded (...args) { return electron.ipcRenderer.invoke('afterViewLoaded', ...args) }
299
+ setWindowButtonPosition (...args) { return electron.ipcRenderer.invoke('setWindowButtonPosition', ...args) }
300
+ setWindowButtonVisibility (...args) { return electron.ipcRenderer.invoke('setWindowButtonVisibility', ...args) }
301
+ async requestIdentity (...args) {
302
+ const publicKey = await electron.ipcRenderer.invoke('requestIdentity', ...args)
303
+ return Buffer.from(publicKey)
304
+ }
305
+
306
+ shareIdentity (...args) { return electron.ipcRenderer.invoke('shareIdentity', ...args) }
307
+ clearIdentity (...args) { return electron.ipcRenderer.invoke('clearIdentity', ...args) }
308
+ message (...args) { return electron.ipcRenderer.invoke('message', ...args) }
309
+ checkpoint (...args) { return electron.ipcRenderer.invoke('checkpoint', ...args) }
310
+ versions (...args) { return electron.ipcRenderer.invoke('versions', ...args) }
311
+ restart (...args) { return electron.ipcRenderer.invoke('restart', ...args) }
312
+
313
+ messages (pattern) {
314
+ electron.ipcRenderer.send('messages', pattern)
315
+ const bus = new Iambus()
316
+ electron.ipcRenderer.on('messages', (e, msg) => {
317
+ if (msg === null) bus.end()
318
+ else bus.pub(msg)
319
+ })
320
+ const stream = bus.sub(pattern)
321
+ return stream
322
+ }
323
+
324
+ warming () {
325
+ electron.ipcRenderer.send('warming')
326
+ const stream = new streamx.Readable()
327
+ electron.ipcRenderer.on('warming', (e, data) => { stream.push(data) })
328
+ return stream
329
+ }
330
+
331
+ reports () {
332
+ electron.ipcRenderer.send('reports')
333
+ const stream = new streamx.Readable()
334
+ electron.ipcRenderer.on('reports', (e, data) => { stream.push(data) })
335
+ return stream
336
+ }
337
+
338
+ workerRun (link, args) {
339
+ const id = electron.ipcRenderer.sendSync('workerPipeId')
340
+ electron.ipcRenderer.send('workerRun', link, args)
341
+ const stream = new streamx.Duplex({
342
+ write (data, cb) {
343
+ electron.ipcRenderer.send('workerPipeWrite', id, data)
344
+ cb()
345
+ },
346
+ final (cb) {
347
+ electron.ipcRenderer.send('workerPipeEnd', id)
348
+ cb()
349
+ }
350
+ })
351
+ electron.ipcRenderer.on('workerPipeError', (e, stack) => {
352
+ stream.emit('error', new Error('Worker PipeError (from electron-main): ' + stack))
353
+ })
354
+ electron.ipcRenderer.on('workerPipeClose', () => { stream.destroy() })
355
+ electron.ipcRenderer.on('workerPipeEnd', () => { stream.end() })
356
+ stream.once('close', () => {
357
+ electron.ipcRenderer.send('workerPipeClose', id)
358
+ })
359
+
360
+ electron.ipcRenderer.on('workerPipeData', (e, data) => { stream.push(data) })
361
+ return stream
362
+ }
363
+
364
+ ref () {}
365
+ unref () {}
366
+ }
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ /** @typedef {import('pear-interface')} */ /* global Pear */
2
+ 'use strict'
3
+ module.exports = Pear.constructor.UI ? Pear[Pear.constructor.UI] : require('./runtime')
@@ -0,0 +1,155 @@
1
+ 'use strict'
2
+ const { platform, arch, isWindows } = require('which-runtime')
3
+ const path = require('path')
4
+ const { command, flag, rest } = require('paparam')
5
+ const Corestore = require('corestore')
6
+ const Localdrive = require('localdrive')
7
+ const Hyperdrive = require('hyperdrive')
8
+ const Hyperswarm = require('hyperswarm')
9
+ const goodbye = global.Pear?.teardown || require('graceful-goodbye')
10
+ const byteSize = require('tiny-byte-size')
11
+ const { decode } = require('hypercore-id-encoding')
12
+ const Rache = require('rache')
13
+ const speedometer = require('speedometer')
14
+ const isTTY = global.Pear ? false : process.stdout.isTTY // TODO: support Pear
15
+ const argv = global.Pear?.config.args || global.Bare?.argv || global.process.argv
16
+ const parser = command('bootstrap',
17
+ flag('--archdump'),
18
+ flag('--dlruntime'),
19
+ flag('--external-corestore'),
20
+ rest('rest')
21
+ )
22
+ const cmd = parser.parse(argv.slice(2), { sync: true })
23
+
24
+ const ARCHDUMP = cmd.flags.archdump === true
25
+ const DLRUNTIME = cmd.flags.dlruntime === true
26
+ const RUNTIMES_DRIVE_KEY = cmd.rest?.[0] || 'gd4n8itmfs6x7tzioj6jtxexiu4x4ijiu3grxdjwkbtkczw5dwho'
27
+ const CORESTORE = `/tmp/pear-archdump/${RUNTIMES_DRIVE_KEY}`
28
+ const ROOT = global.Pear ? path.join(new URL(global.Pear.config.applink).pathname, __dirname) : __dirname
29
+ const ADDON_HOST = require.addon?.host || platform + '-' + arch
30
+ const SWAP = path.join(ROOT, '..')
31
+ const HOST = path.join(SWAP, 'by-arch', ADDON_HOST)
32
+
33
+ module.exports = (all = true) => download(RUNTIMES_DRIVE_KEY, all)
34
+ module.exports.ARCHDUMP = ARCHDUMP
35
+ module.exports.DLRUNTIME = DLRUNTIME
36
+ module.exports.HOST = HOST
37
+
38
+ async function download (key, all = false) {
39
+ if (all) console.log('🍐 Fetching all runtimes from: \n ' + key)
40
+ else console.log('🍐 [ localdev ] - no local runtime: fetching runtime')
41
+
42
+ const store = CORESTORE
43
+
44
+ const maxCacheSize = 65536
45
+ const globalCache = new Rache({ maxSize: maxCacheSize })
46
+
47
+ const corestore = new Corestore(store, { globalCache })
48
+ let runtimes = new Hyperdrive(corestore, decode(key))
49
+
50
+ const swarm = new Hyperswarm()
51
+ goodbye(() => swarm.destroy())
52
+
53
+ swarm.on('connection', (socket) => { runtimes.corestore.replicate(socket) })
54
+
55
+ await runtimes.ready()
56
+
57
+ swarm.join(runtimes.discoveryKey, { server: false, client: true })
58
+ const done = runtimes.corestore.findingPeers()
59
+ swarm.flush().then(done, done)
60
+
61
+ await runtimes.core.update() // make sure we have latest version
62
+
63
+ runtimes = runtimes.checkout(runtimes.version)
64
+ goodbye(() => runtimes.close())
65
+
66
+ console.log(`\n Extracting platform runtime${all ? 's' : ''} to disk`)
67
+
68
+ const runtime = runtimes.mirror(new Localdrive(SWAP), {
69
+ prefix: '/by-arch' + (all ? '' : '/' + ADDON_HOST)
70
+ })
71
+
72
+ const monitor = monitorDrive(runtimes)
73
+ goodbye(() => monitor.stop())
74
+
75
+ for await (const { op, key, bytesAdded } of runtime) {
76
+ if (isTTY) monitor.clear()
77
+ if (op === 'add') {
78
+ console.log('\x1B[32m+\x1B[39m ' + key + ' [' + byteSize(bytesAdded) + ']')
79
+ } else if (op === 'change') {
80
+ console.log('\x1B[33m~\x1B[39m ' + key + ' [' + byteSize(bytesAdded) + ']')
81
+ } else if (op === 'remove') {
82
+ console.log('\x1B[31m-\x1B[39m ' + key + ' [' + byteSize(bytesAdded) + ']')
83
+ }
84
+ }
85
+
86
+ monitor.stop()
87
+
88
+ console.log('\x1B[2K\x1B[200D Runtime extraction complete\x1b[K\n')
89
+
90
+ await runtimes.close()
91
+ await swarm.destroy()
92
+ await corestore.close()
93
+
94
+ const tick = isWindows ? '^' : '✔'
95
+
96
+ if (all) console.log('\x1B[32m' + tick + '\x1B[39m Download complete\n')
97
+ else console.log('\x1B[32m' + tick + '\x1B[39m Download complete, initalizing...\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n')
98
+ }
99
+
100
+ /**
101
+ * @param {Hyperdrive} drive
102
+ */
103
+ function monitorDrive (drive) {
104
+ if (!isTTY) {
105
+ return {
106
+ clear: () => null,
107
+ stop: () => null
108
+ }
109
+ }
110
+
111
+ const downloadSpeedometer = speedometer()
112
+ const uploadSpeedometer = speedometer()
113
+ let peers = 0
114
+ let downloadedBytes = 0
115
+ let uploadedBytes = 0
116
+
117
+ drive.getBlobs().then(blobs => {
118
+ blobs.core.on('download', (_index, bytes) => {
119
+ downloadedBytes += bytes
120
+ downloadSpeedometer(bytes)
121
+ })
122
+ blobs.core.on('upload', (_index, bytes) => {
123
+ uploadedBytes += bytes
124
+ uploadSpeedometer(bytes)
125
+ })
126
+ blobs.core.on('peer-add', () => {
127
+ peers = blobs.core.peers.length
128
+ })
129
+ blobs.core.on('peer-remove', () => {
130
+ peers = blobs.core.peers.length
131
+ })
132
+ }).catch(() => {
133
+ // ignore
134
+ })
135
+
136
+ const clear = () => {
137
+ process.stdout.clearLine()
138
+ process.stdout.cursorTo(0)
139
+ }
140
+
141
+ const interval = setInterval(() => {
142
+ clear()
143
+ process.stdout.write(`[⬇ ${byteSize(downloadedBytes)} - ${byteSize(downloadSpeedometer())}/s - ${peers} peers] [⬆ ${byteSize(uploadedBytes)} - ${byteSize(uploadSpeedometer())}/s - ${peers} peers]`)
144
+ }, 500)
145
+
146
+ const stop = () => {
147
+ clearInterval(interval)
148
+ clear()
149
+ }
150
+
151
+ return {
152
+ clear,
153
+ stop
154
+ }
155
+ }
package/lib/bundle.js ADDED
@@ -0,0 +1,33 @@
1
+ 'use strict'
2
+ const Bundle = require('bare-bundle')
3
+ const Localdrive = require('localdrive')
4
+ const DriveBundler = require('drive-bundler')
5
+ const path = require('path')
6
+ const fs = require('fs')
7
+ const dirname = global.Pear?.config.applink ? new URL(global.Pear.config.applink + '/').pathname : path.join(__dirname, '/..')
8
+ async function bundle () {
9
+ const drive = new Localdrive(dirname)
10
+ const b = new Bundle()
11
+
12
+ const cache = {}
13
+ const res = {}
14
+
15
+ const { entrypoint, resolutions, sources } = await DriveBundler.bundle(drive, { cache, cwd: dirname, entrypoint: '/boot.js', absoluteFiles: false })
16
+
17
+ for (const [key, map] of Object.entries(resolutions)) {
18
+ res[key] = map
19
+ }
20
+
21
+ for (const [key, source] of Object.entries(sources)) {
22
+ cache[key] = true
23
+ b.write(key, source)
24
+ }
25
+
26
+ b.main = entrypoint
27
+ b.resolutions = res
28
+
29
+ await fs.promises.writeFile(dirname + 'boot.bundle', b.toBuffer())
30
+ console.log('boot.bundle generated')
31
+ }
32
+
33
+ module.exports = bundle
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "pear-electron",
3
+ "version": "0.0.1",
4
+ "description": "Pear User-Interface Library for Electron",
5
+ "main": "index.js",
6
+ "bin": "bin.js",
7
+ "scripts": {
8
+ "archdump": "node scripts/bootstrap.js --archdump",
9
+ "bootstrap": "node scripts/bootstrap.js",
10
+ "decal": "node scripts/decal.js",
11
+ "bundle": "node scripts/bundle.js",
12
+ "generate": "npm run decal && npm run bundle",
13
+ "prestage": "npm run archdump && npm run generate"
14
+ },
15
+ "files": [
16
+ "bin.js",
17
+ "scripts/",
18
+ "lib/",
19
+ "boot.js",
20
+ "decal.html",
21
+ "electron-main.js",
22
+ "fonts.css",
23
+ "gui/",
24
+ "index.js",
25
+ "preload.js",
26
+ "runtime.js"
27
+ ],
28
+ "pear": {
29
+ "runtimes": "pear://0.2356.pqbzjhqyonxprx8hghxexnmctw75mr91ewqw5dxe1zmntfyaddqy",
30
+ "name": "pear-electron",
31
+ "stage": {
32
+ "ignore": [
33
+ ".git",
34
+ ".gitignore",
35
+ ".github",
36
+ ".DS_Store",
37
+ ".vscode",
38
+ ".npmrc",
39
+ "scripts",
40
+ "package-lock.json",
41
+ "node_modules",
42
+ "node_modules",
43
+ "gui",
44
+ "boot.js",
45
+ "decal.html",
46
+ "electron-main.js",
47
+ "fonts.css",
48
+ "index.js",
49
+ "preload.js",
50
+ "README.md",
51
+ "runtime.js"
52
+ ]
53
+ }
54
+ },
55
+ "keywords": [
56
+ "pear",
57
+ "runtime",
58
+ "electron",
59
+ "Pear Runtime",
60
+ "peer-to-peer",
61
+ "user-interface",
62
+ "UI",
63
+ "interface"
64
+ ],
65
+ "author": "Holepunch",
66
+ "license": "Apache-2.0",
67
+ "dependencies": {
68
+ "bare-env": "^3.0.0",
69
+ "bare-fs": "^4.0.1",
70
+ "bare-os": "^3.3.0",
71
+ "bare-path": "^3.0.0",
72
+ "bare-subprocess": "^4.0.3",
73
+ "bare-tty": "^4.0.2",
74
+ "corestore": "^6.18.4",
75
+ "fs": "npm:bare-node-fs@^1.0.2",
76
+ "hypercore-id-encoding": "^1.3.0",
77
+ "hyperdrive": "^11.13.3",
78
+ "hyperswarm": "^4.8.4",
79
+ "iambus": "^1.0.3",
80
+ "localdrive": "^1.12.1",
81
+ "paparam": "^1.6.1",
82
+ "path": "npm:bare-node-path@^1.0.1",
83
+ "pear-api": "^0.0.17",
84
+ "pear-interface": "^1.0.3",
85
+ "pear-ipc": "^3.0.3",
86
+ "pear-link": "^2.0.6",
87
+ "pear-updater-bootstrap": "github:holepunchto/pear-updater-bootstrap#corestore-option",
88
+ "rache": "^1.0.0",
89
+ "safety-catch": "^1.0.2",
90
+ "script-linker": "^2.5.3",
91
+ "streamx": "^2.20.2",
92
+ "tiny-byte-size": "^1.1.0",
93
+ "url-file-url": "^1.0.4",
94
+ "which-runtime": "^1.2.1"
95
+ },
96
+ "devDependencies": {
97
+ "@fontsource/open-sans": "^5.1.0",
98
+ "graceful-goodbye": "^1.3.2",
99
+ "redhat-overpass-font": "^1.0.0"
100
+ }
101
+ }