pinokiod 3.9.0 → 3.9.3

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.
Files changed (119) hide show
  1. package/:w +1247 -0
  2. package/kernel/api/filepicker/index.js +59 -0
  3. package/kernel/api/fs/index.js +6 -4
  4. package/kernel/api/index.js +123 -37
  5. package/kernel/api/input/index.js +2 -0
  6. package/kernel/api/web/index.js +6 -0
  7. package/kernel/bin/caddy.js +127 -0
  8. package/kernel/bin/cloudflared.js +1 -0
  9. package/kernel/bin/conda.js +10 -2
  10. package/kernel/bin/cuda.js +0 -16
  11. package/kernel/bin/ffmpeg.js +4 -6
  12. package/kernel/bin/git.js +55 -29
  13. package/kernel/bin/gxx.js +8 -6
  14. package/kernel/bin/huggingface.js +4 -5
  15. package/kernel/bin/index.js +347 -88
  16. package/kernel/bin/node.js +13 -6
  17. package/kernel/bin/py.js +1 -1
  18. package/kernel/bin/setup.js +146 -0
  19. package/kernel/bin/uv.js +4 -5
  20. package/kernel/bin/zip.js +7 -8
  21. package/kernel/connect/index.js +25 -0
  22. package/kernel/connect/providers/github/README.md +11 -0
  23. package/kernel/connect/providers/x/README.md +96 -0
  24. package/kernel/connect/providers/x/index.js +152 -0
  25. package/kernel/environment.js +50 -1
  26. package/kernel/index.js +152 -32
  27. package/kernel/info.js +4 -2
  28. package/kernel/kv.js +38 -0
  29. package/kernel/loader.js +13 -3
  30. package/kernel/peer.js +161 -0
  31. package/kernel/procs.js +116 -0
  32. package/kernel/prototype.js +62 -0
  33. package/kernel/router/common.js +42 -0
  34. package/kernel/router/connector.js +81 -0
  35. package/kernel/router/index.js +235 -0
  36. package/kernel/router/localhost_home_router.js +84 -0
  37. package/kernel/router/localhost_port_router.js +15 -0
  38. package/kernel/router/localhost_variable_router.js +37 -0
  39. package/kernel/router/peer_home_router.js +15 -0
  40. package/kernel/router/peer_peer_router.js +26 -0
  41. package/kernel/router/peer_port_router.js +45 -0
  42. package/kernel/router/peer_variable_router.js +46 -0
  43. package/kernel/router/processor.js +31 -0
  44. package/kernel/shell.js +141 -60
  45. package/kernel/shells.js +32 -17
  46. package/kernel/store.js +58 -0
  47. package/kernel/sysinfo.js +0 -1
  48. package/kernel/util.js +143 -36
  49. package/package.json +4 -1
  50. package/pipe/index.js +0 -2
  51. package/script/index.js +12 -0
  52. package/server/index.js +1473 -553
  53. package/server/public/Socket.js +5 -1
  54. package/server/public/SourceCodePro-Regular.ttf +0 -0
  55. package/server/public/SpaceMono-Bold.ttf +0 -0
  56. package/server/public/SpaceMono-BoldItalic.ttf +0 -0
  57. package/server/public/SpaceMono-Italic.ttf +0 -0
  58. package/server/public/SpaceMono-Regular.ttf +0 -0
  59. package/server/public/commander.js +40 -0
  60. package/server/public/common.js +60 -0
  61. package/server/public/dropzone-min.js +2 -0
  62. package/server/public/dropzone.css +1 -0
  63. package/server/public/filepond-plugin-file-validate-type.min.js +9 -0
  64. package/server/public/filepond-plugin-image-crop.min.js +9 -0
  65. package/server/public/filepond-plugin-image-edit.min.css +8 -0
  66. package/server/public/filepond-plugin-image-edit.min.js +9 -0
  67. package/server/public/filepond-plugin-image-exif-orientation.min.js +9 -0
  68. package/server/public/filepond-plugin-image-preview.min.css +8 -0
  69. package/server/public/filepond-plugin-image-preview.min.js +9 -0
  70. package/server/public/filepond-plugin-image-resize.min.js +9 -0
  71. package/server/public/filepond-plugin-image-transform.min.js +9 -0
  72. package/server/public/filepond.min.css +8 -0
  73. package/server/public/filepond.min.js +9 -0
  74. package/server/public/fscreator.js +174 -0
  75. package/server/public/fseditor.js +212 -0
  76. package/server/public/github.png +0 -0
  77. package/server/public/highlight-js.js +81 -0
  78. package/server/public/highlight.css +9 -0
  79. package/server/public/highlight.js +1244 -0
  80. package/server/public/install.js +17 -20
  81. package/server/public/modalinput.js +105 -9
  82. package/server/public/opener.js +3 -1
  83. package/server/public/pinokio-black.png +0 -0
  84. package/server/public/pinokio-black2.png +0 -0
  85. package/server/public/redoc.standalone.js +1832 -0
  86. package/server/public/style.css +215 -17
  87. package/server/public/swagger-ui-bundle.js +2 -0
  88. package/server/public/swagger-ui.css +3 -0
  89. package/server/public/x.js +63 -0
  90. package/server/socket.js +136 -39
  91. package/server/views/404.ejs +0 -1
  92. package/server/views/app.ejs +368 -98
  93. package/server/views/bootstrap.ejs +22 -19
  94. package/server/views/connect/x.ejs +324 -0
  95. package/server/views/connect.ejs +197 -0
  96. package/server/views/download.ejs +7 -1
  97. package/server/views/editor.ejs +68 -9
  98. package/server/views/explore.ejs +13 -10
  99. package/server/views/file_explorer.ejs +10 -37
  100. package/server/views/github.ejs +218 -0
  101. package/server/views/help.ejs +4 -3
  102. package/server/views/index.ejs +275 -121
  103. package/server/views/install.ejs +56 -29
  104. package/server/views/keys.ejs +276 -0
  105. package/server/views/network.ejs +889 -0
  106. package/server/views/partials/dynamic.ejs +9 -0
  107. package/server/views/partials/menu.ejs +7 -1
  108. package/server/views/prototype/index.ejs +311 -0
  109. package/server/views/prototype/show.ejs +383 -0
  110. package/server/views/redoc.ejs +18 -0
  111. package/server/views/required_env_editor.ejs +11 -2
  112. package/server/views/settings.ejs +38 -10
  113. package/server/views/setup.ejs +254 -0
  114. package/server/views/setup_home.ejs +192 -0
  115. package/server/views/shell.ejs +781 -0
  116. package/server/views/swaggerui.ejs +19 -0
  117. package/server/views/terminal.ejs +174 -42
  118. package/LICENSE +0 -7
  119. package/server/views/proxy.ejs +0 -405
@@ -0,0 +1,146 @@
1
+ const os = require('os')
2
+ let platform = os.platform()
3
+ module.exports = {
4
+ ai: (kernel) => {
5
+ let conda_requirements = [
6
+ "uv",
7
+ "node",
8
+ "huggingface",
9
+ "git",
10
+ "ffmpeg",
11
+ // "caddy"
12
+ ]
13
+ let requirements = [
14
+ { name: "conda", },
15
+ { name: "git", },
16
+ // { name: "zip", },
17
+ { name: "node", },
18
+ { name: "ffmpeg", },
19
+ // { name: "caddy", }
20
+ ]
21
+ if (platform === "win32") {
22
+ requirements.push({ name: "registry" })
23
+ requirements.push({ name: "vs" })
24
+ }
25
+ if (platform === "darwin") {
26
+ requirements.push({ name: "brew" })
27
+ }
28
+ if (platform === "linux") {
29
+ requirements.push({ name: "gxx" })
30
+ conda_requirements.push("gxx")
31
+ }
32
+ if (kernel.gpu === "nvidia") {
33
+ requirements.push({ name: "cuda", })
34
+ conda_requirements.push("cuda")
35
+ }
36
+ requirements = requirements.concat([
37
+ { name: "cloudflared" },
38
+ // { name: "playwright" },
39
+ { name: "huggingface" },
40
+ { name: "uv" },
41
+ { name: "py" },
42
+ ])
43
+ return {
44
+ icon: "fa-solid fa-brain",
45
+ title: "AI",
46
+ description: "Install common modules required for running AI locally",
47
+ requirements,
48
+ conda_requirements
49
+ }
50
+ },
51
+ javascript: (kernel) => {
52
+ return {
53
+ icon: "fa-brands fa-js",
54
+ title: "Node.js",
55
+ description: "Set up self-contained node.js development environment",
56
+ requirements: [
57
+ { name: "conda", },
58
+ { name: "git", },
59
+ { name: "node", },
60
+ ],
61
+ conda_requirements: [
62
+ "node",
63
+ "git",
64
+ ]
65
+ }
66
+ },
67
+ python: (kernel) => {
68
+ return {
69
+ icon: "fa-brands fa-python",
70
+ title: "Python",
71
+ description: "Set up self-contained python development environment",
72
+ requirements: [
73
+ { name: "conda", },
74
+ { name: "git", },
75
+ { name: "uv", },
76
+ ],
77
+ conda_requirements: [
78
+ "uv",
79
+ "git",
80
+ ]
81
+ }
82
+ },
83
+ dev: (kernel) => {
84
+ let requirements = [
85
+ { name: "conda", },
86
+ { name: "git", },
87
+ { name: "node", },
88
+ { name: "uv", },
89
+ ]
90
+ let conda_requirements = [
91
+ "uv",
92
+ "node",
93
+ "git",
94
+ ]
95
+ if (platform === "win32") {
96
+ requirements.push({ name: "registry" })
97
+ requirements.push({ name: "vs" })
98
+ }
99
+ if (platform === "darwin") {
100
+ requirements.push({ name: "brew" })
101
+ }
102
+ if (platform === "linux") {
103
+ requirements.push({ name: "gxx" })
104
+ conda_requirements.push("gxx")
105
+ }
106
+ return {
107
+ icon: "fa-solid fa-laptop-code",
108
+ title: "Coding",
109
+ description: "Install common modules required for development (Node.js, python, Visual Studio Developer Tools (Windows), Xcode build tools (Mac)",
110
+ requirements,
111
+ conda_requirements,
112
+ }
113
+ },
114
+ network: (kernel) => {
115
+ return {
116
+ icon: "fa-solid fa-wifi",
117
+ title: "Network",
118
+ description: "Automatic HTTPS and local network sharing for ALL local apps",
119
+ requirements: [
120
+ { name: "conda", },
121
+ { name: "git", },
122
+ { name: "caddy", },
123
+ ],
124
+ conda_requirements: [
125
+ "git",
126
+ "caddy"
127
+ ]
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
+ }
145
+ }
146
+ }
package/kernel/bin/uv.js CHANGED
@@ -3,16 +3,15 @@ const fetch = require('cross-fetch')
3
3
  const { rimraf } = require('rimraf')
4
4
  const decompress = require('decompress');
5
5
  class UV {
6
+ cmd() {
7
+ return "uv"
8
+ }
6
9
  async install(req, ondata) {
7
10
  await this.kernel.bin.exec({
8
11
  message: [
9
12
  "conda clean -y --all",
10
- "conda install -y -c conda-forge uv",
13
+ `conda install -y -c conda-forge ${this.cmd()}`
11
14
  ]
12
- // conda: {
13
- // name: "base",
14
- // activate: "minimal"
15
- // }
16
15
  }, ondata)
17
16
  }
18
17
  async installed() {
package/kernel/bin/zip.js CHANGED
@@ -1,20 +1,19 @@
1
1
  class Zip {
2
- async install(req, ondata) {
2
+ cmd() {
3
3
  let cmd
4
4
  if (this.kernel.platform === 'win32') {
5
- cmd = "conda install -y -c conda-forge 7zip"
5
+ cmd = "7zip"
6
6
  } else {
7
- cmd = "conda install -y -c conda-forge p7zip"
7
+ cmd = "p7zip"
8
8
  }
9
+ return cmd
10
+ }
11
+ async install(req, ondata) {
9
12
  await this.kernel.bin.exec({
10
13
  message: [
11
14
  "conda clean -y --all",
12
- cmd
15
+ `conda install -y -c conda-forge ${this.cmd()}`
13
16
  ]
14
- // conda: {
15
- // name: "base",
16
- // activate: "minimal"
17
- // }
18
17
  }, ondata)
19
18
  }
20
19
  async installed() {
@@ -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
@@ -439,4 +439,53 @@ const get_raw = async (homedir) => {
439
439
  }
440
440
  return current_env
441
441
  }
442
- module.exports = { ENV, get, get2, init_folders }
442
+
443
+ const requirements = async (script, filepath, kernel) => {
444
+ let pre_items = []
445
+ let requires_instantiation = false
446
+ if (script && script.pre) {
447
+ let env = await get2(filepath, kernel)
448
+ for(let item of script.pre) {
449
+ if (item.env) {
450
+ // if index is not set, use 0 as default (for key)
451
+ if (!item.index) {
452
+ item.index = 0
453
+ }
454
+ if (item.key) {
455
+ const hasProtocol = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(item.key);
456
+ const url = new URL(hasProtocol ? item.key : `https://${item.key}`);
457
+ item.host = url.host
458
+ item.val = await kernel.kv.get(item.host, item.index)
459
+ } else {
460
+ item.host = ""
461
+ }
462
+
463
+ if (env[item.env]) {
464
+ item.val = env[item.env]
465
+ } else {
466
+ if (item.default) {
467
+ if (typeof item.default === 'object') {
468
+ if (item.default.key) {
469
+ const hasProtocol = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(item.default.key);
470
+ const url = new URL(hasProtocol ? item.default.key : `https://${item.default.key}`);
471
+ item.host = url.host
472
+
473
+ let index = item.default.index || 0
474
+ item.index = index
475
+ item.val = await kernel.kv.get(item.host, index)
476
+ } else {
477
+ item.host = ""
478
+ }
479
+ } else {
480
+ item.val = item.default
481
+ }
482
+ }
483
+ requires_instantiation = true
484
+ }
485
+ pre_items.push(item)
486
+ }
487
+ }
488
+ }
489
+ return { items: pre_items, requires_instantiation }
490
+ }
491
+ module.exports = { ENV, get, get2, init_folders, requirements }