pinokiod 3.9.3 → 3.9.12

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/server/index.js CHANGED
@@ -45,6 +45,7 @@ const packagejson = require("../package.json")
45
45
  const Environment = require("../kernel/environment")
46
46
  const Cloudflare = require("../kernel/api/cloudflare")
47
47
  const Util = require("../kernel/util")
48
+ const Info = require("../kernel/info")
48
49
 
49
50
  const Setup = require("../kernel/bin/setup")
50
51
 
@@ -101,11 +102,9 @@ class Server {
101
102
  return new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))
102
103
  }
103
104
  async updateMeta(formData, app_path) {
104
- console.log("updateMeta", app_path)
105
105
  if (formData.icon_dirty) {
106
106
  // write icon file
107
107
  let icon_path = this.kernel.path("api", formData.new_path, formData.icon_path)
108
- console.log({ icon_path })
109
108
  await fs.promises.writeFile(icon_path, formData.avatar)
110
109
  }
111
110
 
@@ -114,7 +113,6 @@ class Server {
114
113
  let meta_path = this.kernel.path("api", app_path, "pinokio.json")
115
114
  console.log("meta_path", meta_path)
116
115
  let meta = (await this.kernel.loader.load(meta_path)).resolved
117
- console.log("meta", meta)
118
116
  if (!meta) meta = {}
119
117
  if (formData.title) {
120
118
  meta.title = formData.title
@@ -124,10 +122,69 @@ class Server {
124
122
  meta.description = formData.description
125
123
  dirty = true
126
124
  }
125
+ if (!meta.plugin) {
126
+ meta.plugin = {
127
+ menu: []
128
+ }
129
+ }
127
130
  if (dirty) {
128
131
  await fs.promises.writeFile(meta_path, JSON.stringify(meta, null, 2))
129
132
  }
130
133
  }
134
+ running_dynamic (name, menu) {
135
+ let cwd = this.kernel.path("api", name)
136
+ let running_dynamic = []
137
+ const traverse = (obj, indexPath) => {
138
+ if (Array.isArray(obj)) {
139
+ for(let i=0; i<obj.length; i++) {
140
+ let item = obj[i]
141
+ let newIndexPath
142
+ if (indexPath) {
143
+ newIndexPath = indexPath + "." + i
144
+ } else {
145
+ newIndexPath = "" + i
146
+ }
147
+ traverse(item, newIndexPath);
148
+ }
149
+ } else if (obj !== null && typeof obj === 'object') {
150
+ for (const key in obj) {
151
+ if (key === 'href') {
152
+ let href = obj[key]
153
+ if (href.startsWith("/api")) {
154
+ let uri_path = new URL("http://localhost" + href).pathname
155
+ let filepath = this.kernel.path(...uri_path.split("/"))
156
+
157
+ let id = `${filepath}?cwd=${cwd}`
158
+ //if (this.kernel.api.running[filepath]) {
159
+ if (this.kernel.api.running[id]) {
160
+ obj.display = "indent"
161
+ running_dynamic.push(obj)
162
+ }
163
+ } else if (href.startsWith("/run")) {
164
+ let uri_path = new URL("http://localhost" + href).pathname
165
+ let _filepath = uri_path.split("/").filter(x=>x).slice(1)
166
+ let filepath = this.kernel.path(..._filepath)
167
+ let id = `${filepath}?cwd=${cwd}`
168
+ //if (this.kernel.api.running[filepath]) {
169
+ if (this.kernel.api.running[id]) {
170
+ obj.display = "indent"
171
+ running_dynamic.push(obj)
172
+ }
173
+ }
174
+ } else if (key === "shell") {
175
+ let shell_id = this.get_shell_id(name, indexPath, obj[key])
176
+ if (this.kernel.api.running[shell_id]) {
177
+ obj.display = "indent"
178
+ running_dynamic.push(obj)
179
+ }
180
+ }
181
+ traverse(obj[key], indexPath);
182
+ }
183
+ }
184
+ }
185
+ traverse(menu)
186
+ return running_dynamic
187
+ }
131
188
  async createMeta(formData) {
132
189
  let _path = this.kernel.path("api", formData.path)
133
190
  await fs.promises.mkdir(_path, { recursive: true }).catch((e) => {})
@@ -139,7 +196,10 @@ class Server {
139
196
  let meta = {
140
197
  title: formData.title,
141
198
  description: formData.description,
142
- icon: "icon.png"
199
+ icon: "icon.png",
200
+ plugin: {
201
+ menu: []
202
+ }
143
203
  }
144
204
  await fs.promises.writeFile(meta_path, JSON.stringify(meta, null, 2))
145
205
  }
@@ -274,7 +334,6 @@ class Server {
274
334
  let error = null
275
335
  if (config && config.version) {
276
336
  let coerced = semver.coerce(config.version)
277
- // console.log("version", { coerced, v: config.version })
278
337
  if (semver.satisfies(coerced, this.kernel.schema)) {
279
338
  console.log("semver satisfied", config.version, this.kernel.schema)
280
339
  } else {
@@ -331,8 +390,8 @@ class Server {
331
390
  }).filter((file) => {
332
391
  return file.name !== "pinokio.js" && file.name !== "pinokio.json" && file.name !== "pinokio_meta.json"
333
392
  })
334
- console.log("files", files)
335
393
  config = {
394
+ init_required: true,
336
395
  icon: config.icon,
337
396
  title: name,
338
397
  menu: files.map((file) => {
@@ -346,7 +405,6 @@ class Server {
346
405
  await this.renderMenu(uri, name, config, [])
347
406
  }
348
407
  let platform = os.platform()
349
- console.log("config before", { config })
350
408
 
351
409
  // if (config.icon) {
352
410
  // //config.iconpath = this.kernel.path("api", name, config.icon)
@@ -358,28 +416,25 @@ class Server {
358
416
  // config.icon = "/pinokio-black.png"
359
417
  // }
360
418
 
361
- console.log("config after", { config })
362
419
 
363
-
364
-
365
- // get all memory variable stied to the current repository
366
- let api_path = this.kernel.path("api", name)
367
- let mem = {}
368
- for(let type in this.kernel.memory) {
369
- // type := local|global
370
- let vars = this.kernel.memory[type]
371
- for(let k in vars) {
372
- if (k.includes(api_path)) {
373
- if (mem[k]) {
374
- mem[k][type] = vars[k]
375
- } else {
376
- mem[k] = {
377
- [type]: vars[k]
378
- }
379
- }
380
- }
381
- }
382
- }
420
+ // // get all memory variable stied to the current repository
421
+ // let api_path = this.kernel.path("api", name)
422
+ // let mem = {}
423
+ // for(let type in this.kernel.memory) {
424
+ // // type := local|global
425
+ // let vars = this.kernel.memory[type]
426
+ // for(let k in vars) {
427
+ // if (k.includes(api_path)) {
428
+ // if (mem[k]) {
429
+ // mem[k][type] = vars[k]
430
+ // } else {
431
+ // mem[k] = {
432
+ // [type]: vars[k]
433
+ // }
434
+ // }
435
+ // }
436
+ // }
437
+ // }
383
438
 
384
439
  await this.init_env("api/" + name)
385
440
 
@@ -418,9 +473,11 @@ class Server {
418
473
  let plugin = await this.getPlugin(name)
419
474
  let plugin_menu = null
420
475
  if (plugin && plugin.menu && Array.isArray(plugin.menu)) {
421
- plugin_menu = plugin.menu
476
+ let running_dynamic = this.running_dynamic(name, plugin.menu)
477
+ plugin_menu = plugin.menu.concat(running_dynamic)
422
478
  }
423
- res.render("app", {
479
+ const result = {
480
+ path: this.kernel.path("api", name),
424
481
  plugin_menu,
425
482
  portal: this.portal,
426
483
  install: this.install,
@@ -428,7 +485,7 @@ class Server {
428
485
  env,
429
486
  mode,
430
487
  port: this.port,
431
- mem,
488
+ // mem,
432
489
  type,
433
490
  platform,
434
491
  running:this.kernel.api.running,
@@ -450,7 +507,8 @@ class Server {
450
507
  src: "/_api/" + name,
451
508
  execUrl: "/api/" + name,
452
509
  // rawpath,
453
- })
510
+ }
511
+ res.render("app", result)
454
512
  }
455
513
  getVariationUrls(req) {
456
514
  let edu = new URL("http://localhost" + req.originalUrl)
@@ -467,6 +525,16 @@ class Server {
467
525
  }
468
526
  return { editorUrl, prevUrl }
469
527
  }
528
+ get_shell_id(name, i, rendered) {
529
+ let hash = crypto.createHash('md5').update(JSON.stringify(rendered)).digest('hex')
530
+ let shell_id
531
+ if (rendered.id) {
532
+ shell_id = encodeURIComponent(`${name}_${rendered.id}`)
533
+ } else {
534
+ shell_id = encodeURIComponent(`${name}_${i}_${hash}`)
535
+ }
536
+ return shell_id
537
+ }
470
538
  async render(req, res, pathComponents, meta) {
471
539
  let base_path = req.base || this.kernel.path("api")
472
540
  let full_filepath = path.resolve(base_path, ...pathComponents)
@@ -734,6 +802,7 @@ class Server {
734
802
  content = await fs.promises.readFile(filepath, "utf8")
735
803
  } catch (e) {
736
804
  content = ""
805
+ console.log(">>>>>>>>>> Error", e)
737
806
  }
738
807
 
739
808
  /********************************************************************
@@ -924,9 +993,11 @@ class Server {
924
993
  execUrl: "~" + req.originalUrl.replace(/^\/_api/, "\/api"),
925
994
  proxies: this.kernel.api.proxies[filepath],
926
995
  cwd: req.query.cwd,
996
+ script_id: (req.base ? `${full_filepath}?cwd=${req.query.cwd}` : null),
927
997
  script_path: (req.base ? full_filepath : null),
928
998
  }
929
999
 
1000
+
930
1001
  res.render(template, result)
931
1002
  }
932
1003
 
@@ -1173,17 +1244,29 @@ class Server {
1173
1244
  // check if there is a running process with this folder name
1174
1245
  let runningApps = new Set()
1175
1246
  for(let key in this.kernel.api.running) {
1176
- let p = this.kernel.path("api", items[i].name) + path.sep
1247
+ //let p = this.kernel.path("api", items[i].name) + path.sep
1248
+ let p = this.kernel.path("api", items[i].name)
1249
+
1177
1250
  //let re = new RegExp(items[i].name)
1178
1251
  //if (re.test(key)) {
1179
1252
  //if (p === key) {
1180
- if (key.includes(p)) {
1253
+
1254
+
1255
+ // not only should include the pattern, but also end with it (otherwise can include similar patterns such as /api/qqqa, /api/qqqaaa, etc.
1256
+ if (key.includes(p) && key.endsWith(p)) {
1181
1257
  items[i].running = true
1182
1258
  items[i].index = index
1183
- if (items[i].running_scripts) {
1259
+ if (!items[i].running_scripts) {
1260
+ items[i].running_scripts = []
1261
+ }
1262
+ if (key.startsWith(p)) {
1184
1263
  items[i].running_scripts.push({ path: path.relative(this.kernel.homedir, key), name: path.relative(p, key) })
1185
1264
  } else {
1186
- items[i].running_scripts = [{ path: path.relative(this.kernel.homedir, key), name: path.relative(p, key) }]
1265
+ let chunks = key.split("?")
1266
+ let dev = chunks[0]
1267
+ let name_chunks = dev.split(path.sep)
1268
+ let name = name_chunks[name_chunks.length-1]
1269
+ items[i].running_scripts.push({ id: key, name })
1187
1270
  }
1188
1271
  index++;
1189
1272
  running.push(items[i])
@@ -1427,7 +1510,7 @@ class Server {
1427
1510
  }
1428
1511
 
1429
1512
 
1430
- async renderMenu(uri, name, config, pathComponents) {
1513
+ async renderMenu(uri, name, config, pathComponents, indexPath) {
1431
1514
  if (config.menu) {
1432
1515
 
1433
1516
  // config.menu = [{
@@ -1454,7 +1537,13 @@ class Server {
1454
1537
  let menuitem = config.menu[i]
1455
1538
 
1456
1539
  if (menuitem.menu) {
1457
- let m = await this.renderMenu(uri, name, { menu: menuitem.menu }, pathComponents)
1540
+ let newIndexPath
1541
+ if (indexPath) {
1542
+ newIndexPath = indexPath + "." + i
1543
+ } else {
1544
+ newIndexPath = "" + i
1545
+ }
1546
+ let m = await this.renderMenu(uri, name, { menu: menuitem.menu }, pathComponents, newIndexPath)
1458
1547
  menuitem.menu = m.menu
1459
1548
  }
1460
1549
 
@@ -1471,11 +1560,28 @@ class Server {
1471
1560
  // file explorer
1472
1561
  config.menu[i].href = path.resolve(this.kernel.homedir, "api", name, menuitem.href)
1473
1562
  } else {
1474
- let absolute = path.resolve(__dirname, ...pathComponents, menuitem.href)
1475
- let seed = path.resolve(__dirname)
1476
- let p = absolute.replace(seed, "")
1477
- let link = p.split(/[\/\\]/).filter((x) => { return x }).join("/")
1478
- config.menu[i].href = "/api/" + name + "/" + link
1563
+ if (menuitem.href.startsWith("/")) {
1564
+ config.menu[i].href = menuitem.href
1565
+ } else {
1566
+ let absolute = path.resolve(__dirname, ...pathComponents, menuitem.href)
1567
+ let seed = path.resolve(__dirname)
1568
+ let p = absolute.replace(seed, "")
1569
+ let link = p.split(/[\/\\]/).filter((x) => { return x }).join("/")
1570
+ config.menu[i].href = "/api/" + name + "/" + link
1571
+ }
1572
+ }
1573
+ } else if (menuitem.run) {
1574
+ let rendered = this.kernel.template.render(menuitem, {})
1575
+ // file explorer
1576
+ if (typeof rendered.run === "object") {
1577
+ let run = rendered.run
1578
+ config.menu[i].run = run.message
1579
+ config.menu[i].cwd = run.path ? path.resolve(this.kernel.homedir, "api", name, run.path) : path.resolve(this.kernel.homedir, "api", name)
1580
+ config.menu[i].href = "/api/" + name
1581
+ } else {
1582
+ config.menu[i].run = rendered.run
1583
+ config.menu[i].cwd = path.resolve(this.kernel.homedir, "api", name)
1584
+ config.menu[i].href = "/api/" + name
1479
1585
  }
1480
1586
  }
1481
1587
  }
@@ -1533,13 +1639,22 @@ class Server {
1533
1639
 
1534
1640
  // deterministic shell id generation
1535
1641
  // `${api_path}_${i}_${hash}`
1536
- let hash = crypto.createHash('md5').update(JSON.stringify(rendered)).digest('hex')
1537
- let shell_id
1538
- if (rendered.id) {
1539
- shell_id = encodeURIComponent(`${name}_${rendered.id}`)
1642
+ let currentIndexPath
1643
+ if (indexPath) {
1644
+ currentIndexPath = indexPath + "." + i
1540
1645
  } else {
1541
- shell_id = encodeURIComponent(`${name}_${i}_${hash}`)
1646
+ currentIndexPath = "" + i
1542
1647
  }
1648
+ let shell_id = this.get_shell_id(name, currentIndexPath, rendered)
1649
+
1650
+
1651
+ // let hash = crypto.createHash('md5').update(JSON.stringify(rendered)).digest('hex')
1652
+ // let shell_id
1653
+ // if (rendered.id) {
1654
+ // shell_id = encodeURIComponent(`${name}_${rendered.id}`)
1655
+ // } else {
1656
+ // shell_id = encodeURIComponent(`${name}_${i}_${hash}`)
1657
+ // }
1543
1658
  menuitem.href = "/shell/" + shell_id + "?" + params.toString()
1544
1659
  let shell = this.kernel.shell.get(shell_id)
1545
1660
  if (shell) {
@@ -1552,9 +1667,16 @@ class Server {
1552
1667
  if (menuitem.href.startsWith("http")) {
1553
1668
  menuitem.src = menuitem.href
1554
1669
  } else if (menuitem.href.startsWith("/")) {
1555
- u = new URL("http://localhost" + menuitem.href)
1556
- u.search = ""
1557
- menuitem.src = u.pathname
1670
+ let run_path = "/run"
1671
+ if (menuitem.href.startsWith(run_path)) {
1672
+ u = new URL("http://localhost" + menuitem.href.slice(run_path.length))
1673
+ u.search = ""
1674
+ menuitem.src = u.pathname
1675
+ } else {
1676
+ u = new URL("http://localhost" + menuitem.href)
1677
+ u.search = ""
1678
+ menuitem.src = u.pathname
1679
+ }
1558
1680
  } else {
1559
1681
  u = new URL("http://localhost/" + menuitem.href)
1560
1682
  u.search = ""
@@ -1563,9 +1685,21 @@ class Server {
1563
1685
 
1564
1686
  // check running
1565
1687
  let fullpath = this.kernel.path(menuitem.src.slice(1))
1566
- if (this.kernel.api.running[fullpath]) {
1567
- menuitem.running = true
1688
+ let relpath = path.relative(this.kernel.homedir, fullpath)
1689
+ if (relpath.startsWith("api")) {
1690
+ // api script
1691
+ if (this.kernel.api.running[fullpath]) {
1692
+ menuitem.running = true
1693
+ }
1694
+ } else {
1695
+ // prototype script
1696
+ let api_path = this.kernel.path("api", name)
1697
+ let id = `${fullpath}?cwd=${api_path}`
1698
+ if (this.kernel.api.running[id]) {
1699
+ menuitem.running = true
1700
+ }
1568
1701
  }
1702
+
1569
1703
 
1570
1704
  }
1571
1705
 
@@ -1637,9 +1771,16 @@ class Server {
1637
1771
  config.menu[i].btn = menuitem.html
1638
1772
  }
1639
1773
  } else if (menuitem.hasOwnProperty("text")) {
1640
-
1641
1774
  if (menuitem.hasOwnProperty("icon")) {
1642
1775
  menuitem.html = `<i class="${menuitem.icon}"></i> ${menuitem.text}`
1776
+ } else if (menuitem.hasOwnProperty("image")) {
1777
+ let imagePath
1778
+ if (menuitem.image.startsWith("/")) {
1779
+ imagePath = menuitem.image
1780
+ } else {
1781
+ imagePath = `/api/${name}/${menuitem.image}?raw=true`
1782
+ }
1783
+ menuitem.html = `<img class='menu-item-image' src='${imagePath}' /> ${menuitem.text}`
1643
1784
  } else {
1644
1785
  menuitem.html = `${menuitem.text}`
1645
1786
  }
@@ -1679,10 +1820,6 @@ class Server {
1679
1820
  })
1680
1821
 
1681
1822
 
1682
-
1683
-
1684
-
1685
-
1686
1823
  // // get all proxies that belong to this repository
1687
1824
  // let childProxies = []
1688
1825
  // for(let scriptPath in this.kernel.api.proxies) {
@@ -2110,17 +2247,15 @@ class Server {
2110
2247
  }
2111
2248
  }
2112
2249
  async getPlugin(name) {
2113
- let api_path = this.kernel.path("api", name)
2114
- let pinokio_json_path = this.kernel.path("api", name, "pinokio.json")
2115
- let pinokio_json = (await this.kernel.loader.load(pinokio_json_path)).resolved
2116
- let plugin_menu = null
2117
- if (pinokio_json && pinokio_json.plugin && pinokio_json.plugin.menu && Array.isArray(pinokio_json.plugin.menu)) {
2118
- let uri = this.kernel.path("api")
2119
- let config = pinokio_json.plugin
2120
- await this.renderMenu(uri, name, config, [])
2121
- return config
2250
+ let info = new Info(this.kernel)
2251
+ info.caller = () => {
2252
+ return this.kernel.path("api", name, "pinokio.js")
2122
2253
  }
2123
- return null
2254
+ let menu = await this.kernel.plugin.config.menu(this.kernel, info)
2255
+ let plugin = { menu }
2256
+ let uri = this.kernel.path("api")
2257
+ await this.renderMenu(uri, name, plugin, [])
2258
+ return plugin
2124
2259
  }
2125
2260
 
2126
2261
  async start(options) {
@@ -2630,7 +2765,6 @@ class Server {
2630
2765
  */
2631
2766
  this.app.post("/connect/:provider/login", ex(async (req, res) => {
2632
2767
  try {
2633
- console.log("params", req.params)
2634
2768
  let response = await this.kernel.connect.login(req.params.provider, req.body)
2635
2769
  res.json(response)
2636
2770
  } catch (e) {
@@ -2639,7 +2773,6 @@ class Server {
2639
2773
  }))
2640
2774
  this.app.post("/connect/:provider/logout", ex(async (req, res) => {
2641
2775
  try {
2642
- console.log("params", req.params)
2643
2776
  await this.kernel.connect.logout(req.params.provider, req.body)
2644
2777
  res.json({ success: true })
2645
2778
  } catch (e) {
@@ -2663,6 +2796,14 @@ class Server {
2663
2796
  res.json({ error: e.message })
2664
2797
  }
2665
2798
  }))
2799
+ this.app.post("/runcmd", ex(async (req, res) => {
2800
+ //Util.openfs(req.body.path, req.body.mode)
2801
+ let cwd = req.body.cwd
2802
+ let cmd = req.body.run
2803
+ console.log({ cmd, cwd })
2804
+ Util.run(cmd, cwd, this.kernel)
2805
+ res.json({ success: true })
2806
+ }))
2666
2807
  this.app.post("/openfs", ex(async (req, res) => {
2667
2808
  //Util.openfs(req.body.path, req.body.mode)
2668
2809
  Util.openfs(req.body.path, req.body, this.kernel)
@@ -2864,13 +3005,11 @@ class Server {
2864
3005
  }
2865
3006
  */
2866
3007
 
2867
- console.log("SHELLS", this.kernel.shell.shells.map((s) => { return { id: s.id, message: s.params.message } }))
2868
3008
  // create a new term from cwd
2869
3009
  let id = decodeURIComponent(req.params.id)
2870
3010
  let cwd = this.kernel.path(this.kernel.api.filePath(decodeURIComponent(req.query.path)))
2871
3011
  let message = req.query.message ? decodeURIComponent(req.query.message) : null
2872
3012
  //let message = req.query.message ? req.query.message : null
2873
- console.log({ message })
2874
3013
  let venv = req.query.venv ? decodeURIComponent(req.query.venv) : null
2875
3014
  let input = req.query.input ? true : false
2876
3015
  let callback = req.query.callback ? decodeURIComponent(req.query.callback) : null
@@ -2906,7 +3045,6 @@ class Server {
2906
3045
  // }
2907
3046
 
2908
3047
  let shell = this.kernel.shell.get(id)
2909
- console.log({ shell })
2910
3048
  res.render("shell", {
2911
3049
  theme: this.theme,
2912
3050
  agent: this.agent,
@@ -2972,12 +3110,8 @@ class Server {
2972
3110
  4. mode:connect => conda, git, caddy
2973
3111
  */
2974
3112
 
2975
- console.log("setup mode", req.params.mode)
2976
-
2977
3113
  let bin = this.kernel.bin.preset(req.params.mode)
2978
3114
 
2979
- console.log("__ bin", bin)
2980
-
2981
3115
  let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
2982
3116
  bin
2983
3117
  })
@@ -2988,7 +3122,6 @@ class Server {
2988
3122
  requirements[i].dependencies = bin.conda_requirements
2989
3123
  }
2990
3124
  }
2991
- console.log("RE", JSON.stringify(requirements, null, 2))
2992
3125
  let current = req.query.callback || req.originalUrl
2993
3126
  res.render("setup", {
2994
3127
  error,
@@ -3010,7 +3143,6 @@ class Server {
3010
3143
  let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
3011
3144
  bin: this.kernel.bin.preset("network"),
3012
3145
  })
3013
- console.log({ requirements, install_required, requirements_pending })
3014
3146
 
3015
3147
  if (!requirements_pending && install_required) {
3016
3148
  res.redirect("/setup/network?callback=/network")
@@ -3149,14 +3281,17 @@ class Server {
3149
3281
 
3150
3282
 
3151
3283
  // write title/description to pinokio.json
3152
- let meta_path = path.resolve(folder_path, "pinokio.json")
3153
- let meta = {
3154
- title: "No title",
3155
- description: "",
3156
- icon: "icon.png"
3157
- }
3158
- console.log({ folder_path, default_icon_path, icon_path, meta_path, meta })
3159
- await fs.promises.writeFile(meta_path, JSON.stringify(meta, null, 2))
3284
+ // let meta_path = path.resolve(folder_path, "pinokio.json")
3285
+ // let meta = {
3286
+ // title: "No title",
3287
+ // description: "",
3288
+ // icon: "icon.png",
3289
+ // plugin: {
3290
+ // menu: []
3291
+ // }
3292
+ // }
3293
+ // console.log({ folder_path, default_icon_path, icon_path, meta_path, meta })
3294
+ // await fs.promises.writeFile(meta_path, JSON.stringify(meta, null, 2))
3160
3295
 
3161
3296
  res.json({
3162
3297
  success: "/pinokio/browser/"+folder
@@ -3271,9 +3406,32 @@ class Server {
3271
3406
  }))
3272
3407
  this.app.get("/prototype/run/*", ex(async (req, res) => {
3273
3408
  let pathComponents = req.params[0].split("/").concat("pinokio.js")
3409
+ let config = await this.kernel.api.meta({ path: req.query.path })
3410
+ let pinokiojson_path = path.resolve(req.query.path, "pinokio.json")
3411
+ let pinokiojson = await this.kernel.require(pinokiojson_path)
3412
+ if (pinokiojson) {
3413
+ if (pinokiojson.plugin) {
3414
+ if (pinokiojson.plugin.menu) {
3415
+ } else {
3416
+ pinokiojson.plugin.menu = []
3417
+ await fs.promises.writeFile(pinokiojson_path, JSON.stringify(pinokiojson, null, 2))
3418
+ }
3419
+ } else {
3420
+ pinokiojson.plugin = { menu: [] }
3421
+ await fs.promises.writeFile(pinokiojson_path, JSON.stringify(pinokiojson, null, 2))
3422
+ }
3423
+ } else {
3424
+ pinokiojson = {
3425
+ plugin: {
3426
+ menu: []
3427
+ }
3428
+ }
3429
+ await fs.promises.writeFile(pinokiojson_path, JSON.stringify(pinokiojson, null, 2))
3430
+ }
3274
3431
  req.base = this.kernel.path("prototype")
3275
- req.query.callback = "/pinokio/browser/" + req.query.api_path
3276
- req.query.cwd = this.kernel.path("api", req.query.api_path)
3432
+ req.query.callback = config.ui
3433
+ //req.query.callback = config.browse
3434
+ req.query.cwd = req.query.path
3277
3435
  await this.render(req, res, pathComponents, null)
3278
3436
  }))
3279
3437
  this.app.get("/prototype/show/*", ex(async (req, res) => {
@@ -3282,7 +3440,10 @@ class Server {
3282
3440
  let title = this.kernel.proto.kv[name].title
3283
3441
  let description = this.kernel.proto.kv[name].description
3284
3442
  let readme = await this.kernel.proto.readme(name)
3443
+ let config = await this.kernel.api.meta({ path: req.query.path })
3285
3444
  res.render("prototype/show", {
3445
+ config,
3446
+ path: req.query.path,
3286
3447
  icon,
3287
3448
  title,
3288
3449
  description,
@@ -3290,7 +3451,7 @@ class Server {
3290
3451
  prototype_path: name,
3291
3452
  portal: this.portal,
3292
3453
  readme,
3293
- items: this.kernel.proto.items,
3454
+ items: this.kernel.proto.items.filter(item => item.type === 'init'),
3294
3455
  logo: this.logo,
3295
3456
  theme: this.theme,
3296
3457
  agent: this.agent,
@@ -3298,9 +3459,28 @@ class Server {
3298
3459
  })
3299
3460
  }))
3300
3461
  this.app.get("/prototype", ex(async (req, res) => {
3462
+ // load meta
3463
+ let config = await this.kernel.api.meta({ path: req.query.path })
3464
+ let items = this.kernel.proto.items
3465
+ if (req.query.type) {
3466
+ items = this.kernel.proto.items.filter(item => item.type === req.query.type)
3467
+ }
3468
+ let title
3469
+ let description
3470
+ if (req.query.type === "init") {
3471
+ title = "Initialize"
3472
+ description = "Select an option to intitialize the project with. This may overwrite the folder if you already have existing files"
3473
+ } else if (req.query.type === "extension") {
3474
+ title = "Extensions"
3475
+ description = "Add extension modules to the current folder"
3476
+ }
3301
3477
  res.render("prototype/index", {
3478
+ title,
3479
+ description,
3480
+ config,
3481
+ path: req.query.path,
3302
3482
  portal: this.portal,
3303
- items: this.kernel.proto.items,
3483
+ items,
3304
3484
  logo: this.logo,
3305
3485
  theme: this.theme,
3306
3486
  agent: this.agent,
@@ -3318,7 +3498,6 @@ class Server {
3318
3498
  id
3319
3499
  }
3320
3500
  */
3321
- console.log("req.body", req.body)
3322
3501
  let formData = req.body
3323
3502
  for(let key in req.files) {
3324
3503
  let file = req.files[key]
@@ -3357,7 +3536,6 @@ class Server {
3357
3536
  id
3358
3537
  }
3359
3538
  */
3360
- console.log("req.body", req.body)
3361
3539
  let formData = req.body
3362
3540
  for(let key in req.files) {
3363
3541
  let file = req.files[key]
@@ -3626,7 +3804,6 @@ class Server {
3626
3804
  let pathComponents = req.params[0].split("/")
3627
3805
  let filepath = path.resolve(this.kernel.homedir, req.params[0])
3628
3806
  const content = await fs.promises.readFile(filepath, "utf8")
3629
- console.log({ pathComponents, content })
3630
3807
  res.render("general_editor", {
3631
3808
  theme: this.theme,
3632
3809
  filepath,
@@ -3639,6 +3816,20 @@ class Server {
3639
3816
  res.json(this.startScripts)
3640
3817
  }
3641
3818
  }))
3819
+ this.app.get("/asset/*", ex((req, res) => {
3820
+ let pathComponents = req.params[0].split("/")
3821
+ let filepath = this.kernel.path(...pathComponents)
3822
+ try {
3823
+ if (req.query.frame) {
3824
+ let m = mime.lookup(filepath)
3825
+ res.type("text/plain")
3826
+ }
3827
+ //res.setHeader('Content-Disposition', 'inline');
3828
+ res.sendFile(filepath)
3829
+ } catch (e) {
3830
+ res.status(404).send(e.message);
3831
+ }
3832
+ }))
3642
3833
  this.app.get("/raw/*", ex((req, res) => {
3643
3834
  let pathComponents = req.params[0].split("/")
3644
3835
  let filepath = this.kernel.path("api", ...pathComponents)
@@ -3662,6 +3853,15 @@ class Server {
3662
3853
  res.status(404).send(e.message)
3663
3854
  }
3664
3855
  }))
3856
+ this.app.get("/run/*", ex(async (req, res) => {
3857
+ let pathComponents = req.params[0].split("/")
3858
+ req.base = this.kernel.homedir
3859
+ try {
3860
+ await this.render(req, res, pathComponents)
3861
+ } catch (e) {
3862
+ res.status(404).send(e.message)
3863
+ }
3864
+ }))
3665
3865
  this.app.get("/api/*", ex(async (req, res) => {
3666
3866
  let pathComponents = req.params[0].split("/")
3667
3867
  if (req.query && 'command' in req.query) {
@@ -3698,10 +3898,10 @@ class Server {
3698
3898
  }))
3699
3899
  this.app.get("/pinokio/dynamic/:name", ex(async (req, res) => {
3700
3900
  let plugin = await this.getPlugin(req.params.name)
3701
- let plugin_menu = null
3702
3901
  let html = ""
3703
3902
  if (plugin && plugin.menu && Array.isArray(plugin.menu)) {
3704
- plugin_menu = plugin.menu
3903
+ let running_dynamic = this.running_dynamic(req.params.name, plugin.menu)
3904
+ plugin.menu = plugin.menu.concat(running_dynamic)
3705
3905
  html = await new Promise((resolve, reject) => {
3706
3906
  ejs.renderFile(path.resolve(__dirname, "views/partials/dynamic.ejs"), { dynamic: plugin.menu }, (err, html) => {
3707
3907
  resolve(html)
@@ -3735,7 +3935,6 @@ class Server {
3735
3935
  }).filter((file) => {
3736
3936
  return file.name !== "pinokio.js" && file.name !== "pinokio.json" && file.name !== "pinokio_meta.json"
3737
3937
  })
3738
- console.log("files", files)
3739
3938
  config = {
3740
3939
  title: name,
3741
3940
  menu: files.map((file) => {
@@ -3769,7 +3968,6 @@ class Server {
3769
3968
  }))
3770
3969
  this.app.post("/pinokio/peer/refresh", ex(async (req, res) => {
3771
3970
  // refresh and broadcast
3772
- console.log("/peer/refresh")
3773
3971
  await this.kernel.refresh()
3774
3972
  res.json({ success: true })
3775
3973
  }))