pinokiod 3.8.1530 → 3.8.1533
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/kernel/api/index.js +27 -7
- package/kernel/api/web/index.js +6 -0
- package/kernel/bin/git.js +36 -10
- package/kernel/bin/index.js +2 -21
- package/kernel/bin/setup.js +16 -0
- package/kernel/connect/index.js +25 -0
- package/kernel/connect/providers/github/README.md +11 -0
- package/kernel/connect/providers/x/README.md +96 -0
- package/kernel/connect/providers/x/index.js +152 -0
- package/kernel/index.js +2 -45
- package/kernel/prototype.js +1 -1
- package/kernel/router/index.js +10 -0
- package/kernel/shell.js +1 -1
- package/package.json +3 -1
- package/script/index.js +12 -0
- package/server/index.js +421 -79
- package/server/public/common.js +28 -0
- package/server/public/fscreator.js +32 -15
- package/server/public/highlight-js.js +81 -0
- package/server/public/highlight.css +9 -0
- package/server/public/highlight.js +1244 -0
- package/server/public/style.css +10 -3
- package/server/public/x.js +63 -0
- package/server/views/500.ejs +1 -1
- package/server/views/app.ejs +73 -8
- package/server/views/connect/x.ejs +324 -0
- package/server/views/connect.ejs +197 -0
- package/server/views/editor.ejs +38 -9
- package/server/views/explore.ejs +4 -9
- package/server/views/file_explorer.ejs +4 -39
- package/server/views/github.ejs +218 -0
- package/server/views/help.ejs +1 -7
- package/server/views/index.ejs +25 -44
- package/server/views/network.ejs +16 -6
- package/server/views/partials/dynamic.ejs +6 -0
- package/server/views/prototype.ejs +299 -0
- package/server/views/settings.ejs +14 -16
- package/server/views/setup_home.ejs +3 -2
- package/server/views/shell.ejs +1 -1
- package/server/views/terminal.ejs +56 -21
- package/LICENSE +0 -0
- package/server/views/local_editor.ejs +0 -282
- package/server/views/prototypes.ejs +0 -482
package/kernel/api/index.js
CHANGED
|
@@ -28,6 +28,21 @@ class Api {
|
|
|
28
28
|
this.child_procs = {}
|
|
29
29
|
this.lproxy = new Lproxy()
|
|
30
30
|
}
|
|
31
|
+
async meta(name) {
|
|
32
|
+
let p = this.kernel.path("api", name, "pinokio.js")
|
|
33
|
+
let pinokio = (await this.kernel.loader.load(p)).resolved
|
|
34
|
+
let p2 = this.kernel.path("api", name, "pinokio_meta.json")
|
|
35
|
+
let pinokio2 = (await this.kernel.loader.load(p2)).resolved
|
|
36
|
+
let p3 = this.kernel.path("api", name, "pinokio.json")
|
|
37
|
+
let pinokio3 = (await this.kernel.loader.load(p3)).resolved
|
|
38
|
+
let meta = Object.assign({}, pinokio, pinokio2, pinokio3)
|
|
39
|
+
meta.iconpath = meta.icon ? this.kernel.path("api", name, meta.icon) : null
|
|
40
|
+
meta.icon = meta.icon ? `/api/${name}/${meta.icon}?raw=true` : "/pinokio-black.png"
|
|
41
|
+
meta.path = this.kernel.path("api", name)
|
|
42
|
+
meta.name = meta.title
|
|
43
|
+
meta.link = `/pinokio/browser/${name}/browse#n1`
|
|
44
|
+
return meta
|
|
45
|
+
}
|
|
31
46
|
get_proxy_url(root, port) {
|
|
32
47
|
if (this.proxies) {
|
|
33
48
|
let proxies = this.proxies[root]
|
|
@@ -160,7 +175,6 @@ class Api {
|
|
|
160
175
|
|
|
161
176
|
await this.kernel.stopCloudflare({ path: requestPath })
|
|
162
177
|
|
|
163
|
-
|
|
164
178
|
// if there are any pending waiters, delete them
|
|
165
179
|
|
|
166
180
|
if (this.waiter[requestPath]) {
|
|
@@ -431,14 +445,18 @@ class Api {
|
|
|
431
445
|
let method
|
|
432
446
|
let dirname
|
|
433
447
|
let mod
|
|
434
|
-
if (req.
|
|
448
|
+
if (req.method && typeof req.method === "function") {
|
|
449
|
+
modpath = null
|
|
450
|
+
method = req.method
|
|
451
|
+
dirname = __dirname
|
|
452
|
+
mod = null
|
|
453
|
+
} else if (req.uri) {
|
|
435
454
|
modpath = this.resolvePath(cwd, req.uri)
|
|
436
455
|
let m = (await this.loader.load(modpath))
|
|
437
456
|
const stats = await fs.promises.stat(modpath)
|
|
438
457
|
if (!this.child_procs[req.parent.path]) {
|
|
439
458
|
this.child_procs[req.parent.path] = new Set()
|
|
440
459
|
}
|
|
441
|
-
console.log("SCRIPT RESOLVE METHOD", req)
|
|
442
460
|
if (this.mods[modpath]) {
|
|
443
461
|
// use the cached module if unchanged
|
|
444
462
|
if (String(stats.mtime) === String(this.mods[modpath].updated)) {
|
|
@@ -572,9 +590,7 @@ class Api {
|
|
|
572
590
|
|
|
573
591
|
}
|
|
574
592
|
async step (request, rawrpc, input, i, total, args) {
|
|
575
|
-
console.time("STEP INIT")
|
|
576
593
|
await Promise.all([this.init(), this.kernel.update_sysinfo()])
|
|
577
|
-
console.timeEnd("STEP INIT")
|
|
578
594
|
|
|
579
595
|
// clear global regular expression object RegExp.lastMatch (memory leak prevention)
|
|
580
596
|
let r = /\s*/g.exec("");
|
|
@@ -583,6 +599,10 @@ class Api {
|
|
|
583
599
|
|
|
584
600
|
let { cwd, script } = await this.resolveScript(request.path)
|
|
585
601
|
|
|
602
|
+
if (request.cwd) {
|
|
603
|
+
cwd = request.cwd
|
|
604
|
+
}
|
|
605
|
+
|
|
586
606
|
let memory = {
|
|
587
607
|
script: this.kernel.script,
|
|
588
608
|
input,
|
|
@@ -635,7 +655,6 @@ class Api {
|
|
|
635
655
|
break;
|
|
636
656
|
}
|
|
637
657
|
}
|
|
638
|
-
|
|
639
658
|
// replace {{{ }}} with {{ }}
|
|
640
659
|
rpc = this.kernel.template.flatten(rpc)
|
|
641
660
|
|
|
@@ -769,6 +788,7 @@ class Api {
|
|
|
769
788
|
uri: request.path
|
|
770
789
|
}
|
|
771
790
|
})
|
|
791
|
+
console.log(">>>>>> STOPPED", request)
|
|
772
792
|
}
|
|
773
793
|
return { request, input: null, step: rpc.next, total: script.run.length, args }
|
|
774
794
|
} else {
|
|
@@ -987,6 +1007,7 @@ class Api {
|
|
|
987
1007
|
uri: request.path
|
|
988
1008
|
}
|
|
989
1009
|
})
|
|
1010
|
+
console.log("<<<<<< STOPPED", request)
|
|
990
1011
|
return { request, input: result, step: rpc.next, total: script.run.length, args }
|
|
991
1012
|
}
|
|
992
1013
|
|
|
@@ -1232,7 +1253,6 @@ class Api {
|
|
|
1232
1253
|
} else {
|
|
1233
1254
|
console.log({ request })
|
|
1234
1255
|
let { cwd, script } = await this.resolveScript(request.path)
|
|
1235
|
-
request.cwd = cwd
|
|
1236
1256
|
|
|
1237
1257
|
if (!script) {
|
|
1238
1258
|
this.ondata({
|
package/kernel/api/web/index.js
CHANGED
|
@@ -21,5 +21,11 @@ class Web {
|
|
|
21
21
|
kernel.exposed[app] = req.params.uri
|
|
22
22
|
console.log("kernel.exposed", kernel.exposed)
|
|
23
23
|
}
|
|
24
|
+
async open(req, ondata, kernel) {
|
|
25
|
+
ondata(req.params, "browser.open")
|
|
26
|
+
}
|
|
27
|
+
async close(req, ondata, kernel) {
|
|
28
|
+
ondata(req.params, "browser.close")
|
|
29
|
+
}
|
|
24
30
|
}
|
|
25
31
|
module.exports = Web
|
package/kernel/bin/git.js
CHANGED
|
@@ -5,15 +5,26 @@ const { rimraf } = require('rimraf')
|
|
|
5
5
|
const path = require("path")
|
|
6
6
|
class Git {
|
|
7
7
|
cmd() {
|
|
8
|
-
|
|
8
|
+
if (this.kernel.platform === "darwin") {
|
|
9
|
+
return "git git-lfs"
|
|
10
|
+
} else {
|
|
11
|
+
return "git git-lfs gh"
|
|
12
|
+
}
|
|
9
13
|
}
|
|
10
14
|
async install(req, ondata) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
15
|
+
if (this.kernel.platform === "darwin") {
|
|
16
|
+
await this.kernel.bin.exec({
|
|
17
|
+
conda: { skip: true },
|
|
18
|
+
message: "brew install gh",
|
|
19
|
+
}, ondata)
|
|
20
|
+
} else {
|
|
21
|
+
await this.kernel.bin.exec({
|
|
22
|
+
message: [
|
|
23
|
+
"conda clean -y --all",
|
|
24
|
+
`conda install -y -c conda-forge ${this.cmd()}`
|
|
25
|
+
]
|
|
26
|
+
}, ondata)
|
|
27
|
+
}
|
|
17
28
|
await fs.promises.mkdir(this.kernel.path("config/gh"), { recursive: true }).catch((e) => { })
|
|
18
29
|
// if (this.kernel.platform === 'win32') {
|
|
19
30
|
// let gitconfig_path = path.resolve(this.kernel.homedir, "gitconfig")
|
|
@@ -29,11 +40,26 @@ class Git {
|
|
|
29
40
|
// }
|
|
30
41
|
}
|
|
31
42
|
async installed() {
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
if (this.kernel.platform === "darwin") {
|
|
44
|
+
let gh_config_exists = await this.kernel.exists("config/gh")
|
|
45
|
+
console.log("conda installed", this.kernel.bin.installed.conda)
|
|
46
|
+
return this.kernel.bin.installed.conda && this.kernel.bin.installed.conda.has("git") && this.kernel.bin.installed.brew.has("gh") && gh_config_exists
|
|
47
|
+
} else {
|
|
48
|
+
let gh_config_exists = await this.kernel.exists("config/gh")
|
|
49
|
+
console.log("conda installed", this.kernel.bin.installed.conda)
|
|
50
|
+
return this.kernel.bin.installed.conda && this.kernel.bin.installed.conda.has("git") && this.kernel.bin.installed.conda.has("gh") && gh_config_exists
|
|
51
|
+
}
|
|
34
52
|
}
|
|
35
53
|
async uninstall(req, ondata) {
|
|
36
|
-
|
|
54
|
+
if (this.kernel.platform === "darwin") {
|
|
55
|
+
await this.kernel.bin.exec({ message: "conda remove git" }, ondata)
|
|
56
|
+
await this.kernel.bin.exec({
|
|
57
|
+
conda: { skip: true },
|
|
58
|
+
message: "brew uninstall gh",
|
|
59
|
+
})
|
|
60
|
+
} else {
|
|
61
|
+
await this.kernel.bin.exec({ message: "conda remove git gh" }, ondata)
|
|
62
|
+
}
|
|
37
63
|
}
|
|
38
64
|
env() {
|
|
39
65
|
let gitconfig_path = path.resolve(this.kernel.homedir, "gitconfig")
|
package/kernel/bin/index.js
CHANGED
|
@@ -56,7 +56,6 @@ class Bin {
|
|
|
56
56
|
params.cols = this.client.cols
|
|
57
57
|
params.rows = this.client.rows
|
|
58
58
|
}
|
|
59
|
-
console.log({ params })
|
|
60
59
|
let response = await this.kernel.shell.run(params, null, ondata)
|
|
61
60
|
return response
|
|
62
61
|
}
|
|
@@ -360,17 +359,12 @@ class Bin {
|
|
|
360
359
|
conda_versions[name] = version
|
|
361
360
|
if (name === "conda") {
|
|
362
361
|
conda_check.conda = true
|
|
363
|
-
// //if (String(version) === "24.11.1") {
|
|
364
|
-
// if (String(version) === "24.11.3") {
|
|
365
|
-
// conda_check.conda = true
|
|
366
|
-
// }
|
|
367
362
|
}
|
|
368
363
|
if (name === "conda-libmamba-solver") {
|
|
369
364
|
//if (String(version) === "24.7.0") {
|
|
370
365
|
let channel = chunks[3]
|
|
371
366
|
let coerced = semver.coerce(version)
|
|
372
367
|
let mamba_requirement = ">=24.11.1"
|
|
373
|
-
// console.log({ name, channel, version })
|
|
374
368
|
//if (semver.satisfies(coerced, mamba_requirement) && channel === "conda-forge") {
|
|
375
369
|
if (semver.satisfies(coerced, mamba_requirement)) {
|
|
376
370
|
conda_check.mamba = true
|
|
@@ -382,16 +376,6 @@ class Bin {
|
|
|
382
376
|
if (String(version) === "3.47.2") {
|
|
383
377
|
conda_check.sqlite = true
|
|
384
378
|
}
|
|
385
|
-
// let coerced = semver.coerce(version)
|
|
386
|
-
// let sqlite_requirement = ">=3.47.2"
|
|
387
|
-
// // console.log({ coerced, version, sqlite_requirement })
|
|
388
|
-
// if (semver.satisfies(coerced, sqlite_requirement)) {
|
|
389
|
-
// console.log("semver satisfied")
|
|
390
|
-
//
|
|
391
|
-
// conda_check.sqlite = true
|
|
392
|
-
// } else {
|
|
393
|
-
// console.log("semver NOT satisfied")
|
|
394
|
-
// }
|
|
395
379
|
}
|
|
396
380
|
}
|
|
397
381
|
} else {
|
|
@@ -443,15 +427,12 @@ class Bin {
|
|
|
443
427
|
|
|
444
428
|
let brew_path = path.resolve(this.kernel.homedir, "bin", "homebrew")
|
|
445
429
|
let brew_exists = await this.exists(brew_path)
|
|
446
|
-
// console.log({ brew_path, brew_exists })
|
|
447
430
|
|
|
448
431
|
let brew = []
|
|
449
432
|
if (brew_exists) {
|
|
450
433
|
start = false
|
|
451
434
|
res = await this.exec({ message: `brew list -1`, conda: { skip: true } }, (stream) => {
|
|
452
|
-
// console.log("brew list check", { stream })
|
|
453
435
|
})
|
|
454
|
-
// console.log("BREW", res.response)
|
|
455
436
|
lines = res.response.split(/[\r\n]+/).slice(0, -1) // ignore last line since it's the prompt
|
|
456
437
|
let end = false
|
|
457
438
|
for(let line of lines) {
|
|
@@ -475,7 +456,6 @@ class Bin {
|
|
|
475
456
|
|
|
476
457
|
|
|
477
458
|
// check brew_installed
|
|
478
|
-
// console.log("checking brew installed")
|
|
479
459
|
let e = await this.kernel.bin.exists("homebrew")
|
|
480
460
|
let { stdout }= await this.exec({ message: "xcode-select -p", conda: { skip: true } }, (stream) => { })
|
|
481
461
|
let e2 = /(.*Library.*Developer.*CommandLineTools.*|.*Xcode.*Developer.*)/gi.test(stdout)
|
|
@@ -736,7 +716,6 @@ class Bin {
|
|
|
736
716
|
// }
|
|
737
717
|
//}
|
|
738
718
|
if (this.kernel.shell) {
|
|
739
|
-
console.log(">>> shell reset")
|
|
740
719
|
this.kernel.shell.reset()
|
|
741
720
|
}
|
|
742
721
|
await this.init()
|
|
@@ -975,6 +954,8 @@ class Bin {
|
|
|
975
954
|
let dependencies
|
|
976
955
|
if (r.name === "conda") {
|
|
977
956
|
dependencies = config.bin.conda_requirements
|
|
957
|
+
console.log("check dependencies", dependencies)
|
|
958
|
+
requirements[i].dependencies = dependencies
|
|
978
959
|
}
|
|
979
960
|
let installed = await this.check_installed(r, dependencies)
|
|
980
961
|
requirements[i].installed = installed
|
package/kernel/bin/setup.js
CHANGED
|
@@ -126,5 +126,21 @@ module.exports = {
|
|
|
126
126
|
"caddy"
|
|
127
127
|
]
|
|
128
128
|
}
|
|
129
|
+
},
|
|
130
|
+
connect: (kernel) => {
|
|
131
|
+
return {
|
|
132
|
+
icon: "fa-solid fa-wifi",
|
|
133
|
+
title: "API Connect",
|
|
134
|
+
description: "Connect with 3rd party APIs",
|
|
135
|
+
requirements: [
|
|
136
|
+
{ name: "conda", },
|
|
137
|
+
{ name: "git", },
|
|
138
|
+
{ name: "caddy", },
|
|
139
|
+
],
|
|
140
|
+
conda_requirements: [
|
|
141
|
+
"git",
|
|
142
|
+
"caddy"
|
|
143
|
+
]
|
|
144
|
+
}
|
|
129
145
|
}
|
|
130
146
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const fetch = require('cross-fetch')
|
|
2
|
+
const X = require('./providers/x')
|
|
3
|
+
class Connect {
|
|
4
|
+
constructor(kernel) {
|
|
5
|
+
this.kernel = kernel
|
|
6
|
+
this.x = new X(kernel)
|
|
7
|
+
}
|
|
8
|
+
async request(provider, method, req) {
|
|
9
|
+
let res = await this[provider].request(method, req)
|
|
10
|
+
return res
|
|
11
|
+
}
|
|
12
|
+
async login(provider, req) {
|
|
13
|
+
let res = await this[provider].login(req)
|
|
14
|
+
return res
|
|
15
|
+
}
|
|
16
|
+
async logout(provider, req) {
|
|
17
|
+
let res = await this[provider].logout(req)
|
|
18
|
+
return res
|
|
19
|
+
}
|
|
20
|
+
async keys(provider) {
|
|
21
|
+
let res = await this[provider].keys()
|
|
22
|
+
return res
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
module.exports = Connect
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
# Usage
|
|
4
|
+
|
|
5
|
+
When you log into Github here, the login will be used for the git installed within Pinokio.
|
|
6
|
+
|
|
7
|
+
Logging into Github lets you do things like:
|
|
8
|
+
|
|
9
|
+
1. Cloning from Private Repositories
|
|
10
|
+
2. Publishing to Github
|
|
11
|
+
3. Use all `gh` CLI commands in all Pinokio shells ([Learn more](https://cli.github.com/))
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
# Usage
|
|
4
|
+
|
|
5
|
+
## 1. Iniitialize
|
|
6
|
+
|
|
7
|
+
First include the script
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script src="https://pinokio.localhost/x.js"></script>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then initialize the X object
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const x = new X()
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 2. Make API Calls
|
|
20
|
+
|
|
21
|
+
Now you can make API calls to X v2 API (Without worrying about authentication). For example:
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
await x.tweet({ text: text })
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The instantiated object `x` is equivalent to the `client.v2` object from [node-twitter-api-v2](https://github.com/PLhery/node-twitter-api-v2)
|
|
28
|
+
|
|
29
|
+
Read the full API documentation here: https://github.com/PLhery/node-twitter-api-v2/blob/master/doc/v2.md
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# Examples
|
|
34
|
+
|
|
35
|
+
## 1. Minimal Post App
|
|
36
|
+
|
|
37
|
+
The authentication is automatically taken care of. You just need to make a POST request to the `/connect/x/api` endpoint, using ANY x.com API.
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<html>
|
|
41
|
+
<body>
|
|
42
|
+
<form>
|
|
43
|
+
<input type='text' id='post'/>
|
|
44
|
+
<input type='submit'>
|
|
45
|
+
</form>
|
|
46
|
+
<script src="https://pinokio.localhost/x.js"></script>
|
|
47
|
+
<script>
|
|
48
|
+
const x = new X()
|
|
49
|
+
document.querySelector("form").addEventListener('submit', async (e) => {
|
|
50
|
+
e.preventDefault()
|
|
51
|
+
let text = document.querySelector("#post").value
|
|
52
|
+
await x.tweet({ text: text })
|
|
53
|
+
})
|
|
54
|
+
</script>
|
|
55
|
+
</body>
|
|
56
|
+
</html>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. Upload Media App
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<html>
|
|
65
|
+
<body>
|
|
66
|
+
<form>
|
|
67
|
+
<input type='file' id='media' name='media'>
|
|
68
|
+
<input type='submit'>
|
|
69
|
+
</form>
|
|
70
|
+
<script src="https://pinokio.localhost/x.js"></script>
|
|
71
|
+
<script>
|
|
72
|
+
const x = new X()
|
|
73
|
+
document.querySelector("form").addEventListener('submit', async (e) => {
|
|
74
|
+
e.preventDefault()
|
|
75
|
+
// 1. get the uploaded file
|
|
76
|
+
let media = document.querySelector("#media").files[0]
|
|
77
|
+
// 2. determine the media_type ("tweet_gif", "tweet_image", or "tweet_video")
|
|
78
|
+
let type = media.type; // e.g., "image/png", "video/mp4", "image/gif"
|
|
79
|
+
let media_category
|
|
80
|
+
if (type.startsWith("image/")) {
|
|
81
|
+
media_category = (type === "image/gif" ? "tweet_gif" : "tweet_image");
|
|
82
|
+
} else if (type.startsWith("video/")) {
|
|
83
|
+
media_category = "tweet_video"
|
|
84
|
+
}
|
|
85
|
+
// 3. upload media
|
|
86
|
+
let media_id = await x.uploadMedia(media, { media_category })
|
|
87
|
+
// 4. post the uploaded media
|
|
88
|
+
let res = await x.tweet({ media: { media_ids: [media_id] }})
|
|
89
|
+
console.log(res)
|
|
90
|
+
})
|
|
91
|
+
</script>
|
|
92
|
+
</body>
|
|
93
|
+
</html>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const fetch = require('cross-fetch')
|
|
4
|
+
const FormData = require('form-data');
|
|
5
|
+
const marked = require('marked')
|
|
6
|
+
const { TwitterApi } = require('twitter-api-v2')
|
|
7
|
+
class X {
|
|
8
|
+
id = 'd2FQZ0U4NXpzYnRyS1hZeHBvbUc6MTpjaQ'
|
|
9
|
+
constructor(kernel) {
|
|
10
|
+
this.kernel = kernel
|
|
11
|
+
}
|
|
12
|
+
async readme() {
|
|
13
|
+
let md = await fs.promises.readFile(path.resolve(__dirname, "README.md"), "utf8")
|
|
14
|
+
return marked.parse(md, {
|
|
15
|
+
//baseUrl: req._parsedUrl.pathname.replace(/^\/_api/, "/raw/") + "/"
|
|
16
|
+
//baseUrl: req.originalUrl + "/"
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
async persist(auth) {
|
|
20
|
+
this.auth = auth
|
|
21
|
+
this.auth.expires_at = Date.now() + this.auth.expires_in * 1000
|
|
22
|
+
let authPath = this.kernel.path('connect/x.json')
|
|
23
|
+
await fs.promises.mkdir(this.kernel.path("connect"), { recursive: true }).catch((e) => { })
|
|
24
|
+
await fs.promises.writeFile(authPath, JSON.stringify(this.auth, null, 2))
|
|
25
|
+
}
|
|
26
|
+
async destroy() {
|
|
27
|
+
await fs.promises.rm(this.kernel.path("connect/x.json"))
|
|
28
|
+
this.auth = null
|
|
29
|
+
}
|
|
30
|
+
async sync() {
|
|
31
|
+
// check if auth exists
|
|
32
|
+
// if not, throw error
|
|
33
|
+
let authPath = this.kernel.path('connect/x.json')
|
|
34
|
+
this.auth = (await this.kernel.loader.load(authPath)).resolved
|
|
35
|
+
if (!this.auth) {
|
|
36
|
+
throw new Error("not authenticated")
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
if (!this.auth.refresh_token) {
|
|
40
|
+
throw new Error("no refresh token")
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// check if auth has expired
|
|
45
|
+
// if expired, refresh and return
|
|
46
|
+
if (Date.now() < this.auth.expires_at) {
|
|
47
|
+
console.log("authentication valid")
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
console.log("auth expired. refresh....", JSON.stringify({ auth: this.auth, id: this.id }, null, 2))
|
|
53
|
+
// expired — refresh
|
|
54
|
+
const response = await fetch('https://api.twitter.com/2/oauth2/token', {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: { 'Content-Type': 'application/json' },
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
grant_type: 'refresh_token',
|
|
59
|
+
refresh_token: this.auth.refresh_token,
|
|
60
|
+
client_id: this.id
|
|
61
|
+
})
|
|
62
|
+
}).then((res) => {
|
|
63
|
+
return res.json()
|
|
64
|
+
});
|
|
65
|
+
await this.persist(response)
|
|
66
|
+
return this.auth
|
|
67
|
+
}
|
|
68
|
+
async keys() {
|
|
69
|
+
await this.sync()
|
|
70
|
+
return this.auth
|
|
71
|
+
}
|
|
72
|
+
async request(method, req) {
|
|
73
|
+
/*
|
|
74
|
+
method := "uploadMedia"
|
|
75
|
+
params := {
|
|
76
|
+
"value.0", val1,
|
|
77
|
+
"type.0": "String",
|
|
78
|
+
"value.1": val2,
|
|
79
|
+
"type.1": "Blob"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
uploadMedia(
|
|
83
|
+
val1,
|
|
84
|
+
{
|
|
85
|
+
key2: val2,
|
|
86
|
+
key3: val3
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
*/
|
|
90
|
+
await this.sync()
|
|
91
|
+
const contentType = req.headers['content-type'];
|
|
92
|
+
let args
|
|
93
|
+
if (contentType.toLowerCase() === "application/json") {
|
|
94
|
+
// don't transform
|
|
95
|
+
args = req.body
|
|
96
|
+
let response = await this.client.v2[method](...args)
|
|
97
|
+
return response
|
|
98
|
+
} else {
|
|
99
|
+
args = []
|
|
100
|
+
let body = Object.assign({}, req.body)
|
|
101
|
+
if (req.files) {
|
|
102
|
+
for (const file of req.files) {
|
|
103
|
+
body[file.fieldname] = file.buffer
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
let types = []
|
|
107
|
+
for(let key in body) {
|
|
108
|
+
let chunks = key.split(".")
|
|
109
|
+
let index = parseInt(chunks[1])
|
|
110
|
+
if (chunks[0] === "type") {
|
|
111
|
+
types[index] = body[key]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for(let key in body) {
|
|
115
|
+
let chunks = key.split(".")
|
|
116
|
+
let index = parseInt(chunks[1])
|
|
117
|
+
if (chunks[0] === "value") {
|
|
118
|
+
let type = types[index]
|
|
119
|
+
if (type === "Object") {
|
|
120
|
+
args[index] = JSON.parse(body[key])
|
|
121
|
+
} else {
|
|
122
|
+
args[index] = body[key]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
console.log({ args, method })
|
|
127
|
+
|
|
128
|
+
this.client = new TwitterApi(this.auth.access_token);
|
|
129
|
+
let response = await this.client.v2[method](...args)
|
|
130
|
+
return response
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async login (req) {
|
|
134
|
+
const authHeader = 'Basic ' + Buffer.from(`${this.id}:`).toString('base64');
|
|
135
|
+
const response = await fetch('https://api.x.com/2/oauth2/token', {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: {
|
|
138
|
+
'Content-Type': 'application/json',
|
|
139
|
+
// 'Authorization': authHeader
|
|
140
|
+
},
|
|
141
|
+
body: JSON.stringify(req.payload)
|
|
142
|
+
}).then((res) => {
|
|
143
|
+
return res.json()
|
|
144
|
+
});
|
|
145
|
+
await this.persist(response)
|
|
146
|
+
return this.auth
|
|
147
|
+
}
|
|
148
|
+
async logout (req) {
|
|
149
|
+
await this.destroy()
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
module.exports = X
|
package/kernel/index.js
CHANGED
|
@@ -33,6 +33,7 @@ const Proto = require('./prototype')
|
|
|
33
33
|
const Router = require("./router")
|
|
34
34
|
const Procs = require('./procs')
|
|
35
35
|
const Peer = require('./peer')
|
|
36
|
+
const Connect = require('./connect')
|
|
36
37
|
//const kill = require('./tree-kill');
|
|
37
38
|
const kill = require('kill-sync')
|
|
38
39
|
const VARS = {
|
|
@@ -45,10 +46,6 @@ const VARS = {
|
|
|
45
46
|
|
|
46
47
|
//const memwatch = require('@airbnb/node-memwatch');
|
|
47
48
|
class Kernel {
|
|
48
|
-
//schema = ">=1.0.0"
|
|
49
|
-
//schema = "<=2.1.0"
|
|
50
|
-
//schema = "<=3.2.0"
|
|
51
|
-
//schema = "<=3.7.0"
|
|
52
49
|
schema = "<=4.0.0"
|
|
53
50
|
constructor(store) {
|
|
54
51
|
this.fetch = fetch
|
|
@@ -81,13 +78,6 @@ class Kernel {
|
|
|
81
78
|
this.jsdom = jsdom
|
|
82
79
|
this.exposed = {}
|
|
83
80
|
this.envs = {}
|
|
84
|
-
// this.info = new Info(this)
|
|
85
|
-
// this.pipe = new Pipe(this)
|
|
86
|
-
// this.proto = new Proto(this)
|
|
87
|
-
// this.processes = new Procs()
|
|
88
|
-
// this.kv = new KV(this)
|
|
89
|
-
// this.cloudflare = new Cloudflare()
|
|
90
|
-
// this.peer = new Peer()
|
|
91
81
|
this.shellpath = shellPath.sync()
|
|
92
82
|
|
|
93
83
|
|
|
@@ -292,41 +282,7 @@ class Kernel {
|
|
|
292
282
|
|
|
293
283
|
// 9. announce self to the peer network
|
|
294
284
|
this.peer.announce()
|
|
295
|
-
|
|
296
285
|
}
|
|
297
|
-
|
|
298
|
-
//if (https_installed && peer_active) {
|
|
299
|
-
|
|
300
|
-
// // 1. get the process list
|
|
301
|
-
// await this.processes.refresh()
|
|
302
|
-
|
|
303
|
-
// // 2. refresh peer info to reflect the proc info
|
|
304
|
-
// await this.peer.refresh()
|
|
305
|
-
|
|
306
|
-
// // 3. load custom routers from ~/pinokio/network
|
|
307
|
-
// await this.router.init()
|
|
308
|
-
|
|
309
|
-
// // 4. set current local host router info
|
|
310
|
-
// await this.router.local()
|
|
311
|
-
|
|
312
|
-
// // 5. refresh peer info to reflect the updated router info
|
|
313
|
-
// await this.peer.refresh()
|
|
314
|
-
|
|
315
|
-
// // 6. tell peers to refresh
|
|
316
|
-
// if (notify_peers) {
|
|
317
|
-
// await this.peer.notify_peers()
|
|
318
|
-
// }
|
|
319
|
-
|
|
320
|
-
// // 7. update remote router
|
|
321
|
-
// await this.router.remote()
|
|
322
|
-
|
|
323
|
-
// // 8. update caddy config
|
|
324
|
-
// await this.router.update()
|
|
325
|
-
|
|
326
|
-
// // 9. announce self to the peer network
|
|
327
|
-
// this.peer.announce()
|
|
328
|
-
|
|
329
|
-
//}
|
|
330
286
|
}
|
|
331
287
|
async clearLog(group) {
|
|
332
288
|
let relativePath = path.relative(this.homedir, group)
|
|
@@ -599,6 +555,7 @@ class Kernel {
|
|
|
599
555
|
this.python = new Python(this)
|
|
600
556
|
this.shell = new Shells(this)
|
|
601
557
|
this.router = new Router(this)
|
|
558
|
+
this.connect = new Connect(this)
|
|
602
559
|
this.system = system
|
|
603
560
|
this.keys = {}
|
|
604
561
|
this.memory = {
|
package/kernel/prototype.js
CHANGED
|
@@ -30,7 +30,7 @@ class Proto {
|
|
|
30
30
|
let proto = path.dirname(prototype_path)
|
|
31
31
|
let pinokiojs = path.resolve(prototype_dir, prototype_path)
|
|
32
32
|
let config = await this.kernel.require(pinokiojs)
|
|
33
|
-
if (config && config.
|
|
33
|
+
if (config && config.run) {
|
|
34
34
|
if (config.icon) {
|
|
35
35
|
config.icon = "/prototype/" + proto + "/" + config.icon
|
|
36
36
|
} else {
|
package/kernel/router/index.js
CHANGED
|
@@ -221,5 +221,15 @@ class Router {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
+
async check() {
|
|
225
|
+
try {
|
|
226
|
+
let res = await axios.get(`http://localhost:2019/config/`, {
|
|
227
|
+
timeout: 2000
|
|
228
|
+
})
|
|
229
|
+
return res.data
|
|
230
|
+
} catch (e) {
|
|
231
|
+
return null
|
|
232
|
+
}
|
|
233
|
+
}
|
|
224
234
|
}
|
|
225
235
|
module.exports = Router
|