pinokiod 3.9.0 → 3.9.2

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 (118) hide show
  1. package/kernel/api/filepicker/index.js +59 -0
  2. package/kernel/api/fs/index.js +6 -4
  3. package/kernel/api/index.js +123 -37
  4. package/kernel/api/input/index.js +2 -0
  5. package/kernel/api/web/index.js +6 -0
  6. package/kernel/bin/caddy.js +127 -0
  7. package/kernel/bin/cloudflared.js +1 -0
  8. package/kernel/bin/conda.js +10 -2
  9. package/kernel/bin/cuda.js +0 -16
  10. package/kernel/bin/ffmpeg.js +4 -6
  11. package/kernel/bin/git.js +55 -29
  12. package/kernel/bin/gxx.js +8 -6
  13. package/kernel/bin/huggingface.js +4 -5
  14. package/kernel/bin/index.js +347 -88
  15. package/kernel/bin/node.js +13 -6
  16. package/kernel/bin/py.js +1 -1
  17. package/kernel/bin/setup.js +146 -0
  18. package/kernel/bin/uv.js +4 -5
  19. package/kernel/bin/zip.js +7 -8
  20. package/kernel/connect/index.js +25 -0
  21. package/kernel/connect/providers/github/README.md +11 -0
  22. package/kernel/connect/providers/x/README.md +96 -0
  23. package/kernel/connect/providers/x/index.js +152 -0
  24. package/kernel/environment.js +50 -1
  25. package/kernel/index.js +152 -32
  26. package/kernel/info.js +4 -2
  27. package/kernel/kv.js +38 -0
  28. package/kernel/loader.js +13 -3
  29. package/kernel/peer.js +161 -0
  30. package/kernel/procs.js +116 -0
  31. package/kernel/prototype.js +62 -0
  32. package/kernel/router/common.js +42 -0
  33. package/kernel/router/connector.js +81 -0
  34. package/kernel/router/index.js +235 -0
  35. package/kernel/router/localhost_home_router.js +84 -0
  36. package/kernel/router/localhost_port_router.js +15 -0
  37. package/kernel/router/localhost_variable_router.js +37 -0
  38. package/kernel/router/peer_home_router.js +15 -0
  39. package/kernel/router/peer_peer_router.js +26 -0
  40. package/kernel/router/peer_port_router.js +45 -0
  41. package/kernel/router/peer_variable_router.js +46 -0
  42. package/kernel/router/processor.js +31 -0
  43. package/kernel/shell.js +141 -60
  44. package/kernel/shells.js +32 -17
  45. package/kernel/store.js +58 -0
  46. package/kernel/sysinfo.js +0 -1
  47. package/kernel/util.js +143 -36
  48. package/package.json +4 -1
  49. package/pipe/index.js +0 -2
  50. package/script/index.js +12 -0
  51. package/server/index.js +1473 -553
  52. package/server/public/Socket.js +5 -1
  53. package/server/public/SourceCodePro-Regular.ttf +0 -0
  54. package/server/public/SpaceMono-Bold.ttf +0 -0
  55. package/server/public/SpaceMono-BoldItalic.ttf +0 -0
  56. package/server/public/SpaceMono-Italic.ttf +0 -0
  57. package/server/public/SpaceMono-Regular.ttf +0 -0
  58. package/server/public/commander.js +40 -0
  59. package/server/public/common.js +60 -0
  60. package/server/public/dropzone-min.js +2 -0
  61. package/server/public/dropzone.css +1 -0
  62. package/server/public/filepond-plugin-file-validate-type.min.js +9 -0
  63. package/server/public/filepond-plugin-image-crop.min.js +9 -0
  64. package/server/public/filepond-plugin-image-edit.min.css +8 -0
  65. package/server/public/filepond-plugin-image-edit.min.js +9 -0
  66. package/server/public/filepond-plugin-image-exif-orientation.min.js +9 -0
  67. package/server/public/filepond-plugin-image-preview.min.css +8 -0
  68. package/server/public/filepond-plugin-image-preview.min.js +9 -0
  69. package/server/public/filepond-plugin-image-resize.min.js +9 -0
  70. package/server/public/filepond-plugin-image-transform.min.js +9 -0
  71. package/server/public/filepond.min.css +8 -0
  72. package/server/public/filepond.min.js +9 -0
  73. package/server/public/fscreator.js +174 -0
  74. package/server/public/fseditor.js +212 -0
  75. package/server/public/github.png +0 -0
  76. package/server/public/highlight-js.js +81 -0
  77. package/server/public/highlight.css +9 -0
  78. package/server/public/highlight.js +1244 -0
  79. package/server/public/install.js +17 -20
  80. package/server/public/modalinput.js +105 -9
  81. package/server/public/opener.js +3 -1
  82. package/server/public/pinokio-black.png +0 -0
  83. package/server/public/pinokio-black2.png +0 -0
  84. package/server/public/redoc.standalone.js +1832 -0
  85. package/server/public/style.css +211 -17
  86. package/server/public/swagger-ui-bundle.js +2 -0
  87. package/server/public/swagger-ui.css +3 -0
  88. package/server/public/x.js +63 -0
  89. package/server/socket.js +136 -39
  90. package/server/views/404.ejs +0 -1
  91. package/server/views/app.ejs +356 -90
  92. package/server/views/bootstrap.ejs +22 -19
  93. package/server/views/connect/x.ejs +324 -0
  94. package/server/views/connect.ejs +197 -0
  95. package/server/views/download.ejs +7 -1
  96. package/server/views/editor.ejs +68 -9
  97. package/server/views/explore.ejs +13 -10
  98. package/server/views/file_explorer.ejs +10 -37
  99. package/server/views/github.ejs +218 -0
  100. package/server/views/help.ejs +4 -3
  101. package/server/views/index.ejs +268 -118
  102. package/server/views/install.ejs +56 -29
  103. package/server/views/keys.ejs +276 -0
  104. package/server/views/network.ejs +889 -0
  105. package/server/views/partials/dynamic.ejs +9 -0
  106. package/server/views/partials/menu.ejs +7 -1
  107. package/server/views/prototype/index.ejs +311 -0
  108. package/server/views/prototype/show.ejs +383 -0
  109. package/server/views/redoc.ejs +18 -0
  110. package/server/views/required_env_editor.ejs +11 -2
  111. package/server/views/settings.ejs +38 -10
  112. package/server/views/setup.ejs +254 -0
  113. package/server/views/setup_home.ejs +192 -0
  114. package/server/views/shell.ejs +781 -0
  115. package/server/views/swaggerui.ejs +19 -0
  116. package/server/views/terminal.ejs +174 -42
  117. package/LICENSE +0 -7
  118. package/server/views/proxy.ejs +0 -405
@@ -0,0 +1,889 @@
1
+ <html>
2
+ <head>
3
+ <title>Pinokio</title>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
6
+ <link href="/xterm.min.css" rel="stylesheet" />
7
+ <link href="/css/fontawesome.min.css" rel="stylesheet">
8
+ <link href="/css/solid.min.css" rel="stylesheet">
9
+ <link href="/css/regular.min.css" rel="stylesheet">
10
+ <link href="/css/brands.min.css" rel="stylesheet">
11
+ <link href="/markdown.css" rel="stylesheet"/>
12
+ <link href="/noty.css" rel="stylesheet"/>
13
+ <link href="/style.css" rel="stylesheet"/>
14
+ <script src="/sweetalert2.js"></script>
15
+ <script src="/commander.js"></script>
16
+ <% if (agent === "electron") { %>
17
+ <link href="/electron.css" rel="stylesheet"/>
18
+ <% } %>
19
+ <style>
20
+ .line2 {
21
+ display: flex;
22
+ align-items: center;
23
+ cursor: pointer;
24
+ background: rgba(0,0,100,0.04);
25
+ }
26
+ .line2 a {
27
+ text-decoration: none;
28
+ color: black;
29
+ }
30
+ .status {
31
+ padding: 10px;
32
+ margin: 10px;
33
+ border-radius: 10px;
34
+ }
35
+ .status.offline {
36
+ background: silver;
37
+ }
38
+ .status.online {
39
+ background: yellowgreen;
40
+ }
41
+ .switch {
42
+ padding: 10px;
43
+ margin: 10px 0;
44
+ }
45
+ .switch[data-online=true] {
46
+ color: yellowgreen;
47
+ }
48
+ .button {
49
+ padding: 10px;
50
+ }
51
+ .on, .off {
52
+ display: flex;
53
+ align-items: center;
54
+ }
55
+ header .runner {
56
+ padding: 10px 0 0;
57
+ }
58
+ .proc-table {
59
+ display: flex;
60
+ }
61
+ .proc-table .title {
62
+ flex-grow: 1;
63
+ }
64
+ .proxy {
65
+ padding: 0 10px;
66
+ text-align: right;
67
+ }
68
+ .proxy a {
69
+ text-decoration: none;
70
+ display: inline-block;
71
+ padding: 5px 10px;
72
+ border-radius: 2px;
73
+ background: black;
74
+ color: white;
75
+ }
76
+ .browser-options-btns {
77
+ display: flex;
78
+ padding-top: 5px;
79
+ }
80
+ .browser-options-row {
81
+ border-top: 1px solid rgba(0,0,0,0.1);
82
+ border-bottom: 1px solid rgba(0,0,0,0.1);
83
+ display: flex;
84
+ padding: 20px 0;
85
+ align-items: flex-start;
86
+ }
87
+ .browser-options-row h3 {
88
+ margin: 0;
89
+ font-size: 14px;
90
+ margin-bottom: 3px;
91
+ }
92
+ .line.align-top h3.table-grid {
93
+ display: grid;
94
+ grid-template-columns: repeat(3, 1fr);
95
+ }
96
+ .browser-options-row .btn.disabled {
97
+ opacity: 0.7;
98
+ }
99
+ .browser-options-row .btn {
100
+ font-weight: bold;
101
+ width: 100px;
102
+ text-align: center;
103
+ display: block;
104
+ margin-right: 10px;
105
+ flex-shrink: 0;
106
+ padding: 5px;
107
+ }
108
+ .badge {
109
+ font-size: 12px;
110
+ padding: 5px 10px;
111
+ background: rgba(0,0,100,0.1);
112
+ border-radius: 5px;
113
+ display: inline-block;
114
+ margin-top: 5px;
115
+ }
116
+ a.badge {
117
+ color: royalblue;
118
+ text-decoration: none;
119
+ cursor: pointer;
120
+ }
121
+ .badge a {
122
+ color: royalblue;
123
+ text-decoration: none;
124
+ }
125
+ body.dark .btn {
126
+ color: white;
127
+ border: 1px solid rgba(255,255,255,0.3);
128
+ }
129
+ body.dark .badge {
130
+ background: rgba(255,255,255,0.1);
131
+ }
132
+ body.dark .browser-options-row {
133
+ border-top: 1px solid rgba(255,255,255,0.05);
134
+ border-bottom: 1px solid rgba(255,255,255,0.05);
135
+ }
136
+ .description a {
137
+ color: royalblue;
138
+ text-decoration: none;
139
+ }
140
+ a.ln[href^=https] {
141
+ color: #56ad00;
142
+ }
143
+ a.ln:hover {
144
+ color: red !important;
145
+ }
146
+ .line.align-top h3 {
147
+ /*
148
+ align-items: flex-start;
149
+ */
150
+ align-items: center;
151
+ }
152
+ .line a:hover {
153
+ color: red;
154
+ }
155
+ .line img {
156
+ width: 40px;
157
+ height: 40px;
158
+ }
159
+ .btn-container {
160
+ margin-top: 10px;
161
+ }
162
+ .header-label {
163
+ padding: 0;
164
+ font-size: 50px;
165
+ letter-spacing: -1px;
166
+ /*
167
+ text-align: center;
168
+ */
169
+ text-transform: capitalize;
170
+ }
171
+ .header-label-sub h1 {
172
+ font-size: 25px;
173
+ letter-spacing: -1px;
174
+ font-weight: bold;
175
+ }
176
+ .header-label-sub {
177
+ font-size: 16px;
178
+ padding: 10px 0;
179
+ border-bottom: 1px solid rgba(0,0,0,0.1);
180
+ }
181
+ .header-label-sub .s {
182
+ padding: 10px 0;
183
+ opacity: 0.7;
184
+ }
185
+ .header-container {
186
+ margin: 10px;
187
+ background: rgba(0, 0, 100, 0.04);
188
+ padding: 20px;
189
+ box-sizing: border-box;
190
+ }
191
+ .container {
192
+ display: grid;
193
+ grid-template-columns: repeat(<%=list.length%>, 1fr);
194
+ }
195
+ .dark .container-row {
196
+ background: rgba(255, 255, 255, 0.04);
197
+ }
198
+ .container-row {
199
+ background: rgba(0, 0, 100, 0.04);
200
+ padding: 15px 30px;
201
+ box-sizing: border-box;
202
+ }
203
+ .container-row.current .header-label-sub {
204
+ color: royalblue;
205
+ }
206
+ /*
207
+ .container-row.current .header-label-sub {
208
+ color: royalblue;
209
+ }
210
+ */
211
+ .desc {
212
+ /*
213
+ text-align:center;
214
+ */
215
+ padding: 10px 0;
216
+ }
217
+ #reset-label {
218
+ color: firebrick;
219
+ }
220
+ .link-label {
221
+ margin-right: 10px;
222
+ text-decoration: underline;
223
+ color: royalblue;
224
+ cursor: pointer;
225
+ }
226
+ .container-row table {
227
+ width: 100%;
228
+ table-layout: fixed;
229
+ }
230
+ table a {
231
+ text-decoration: none;
232
+ color: royalblue;
233
+ }
234
+ td:first-child, th:first-child {
235
+ max-width: 100px;
236
+ }
237
+ .container-row th h2 {
238
+ font-size: 18px;
239
+ margin: 0;
240
+ text-transform: uppercase;
241
+ }
242
+ .container-row th {
243
+ vertical-align: top;
244
+ border-bottom: 1px solid rgba(0,0,0,0.05);
245
+ text-align: left;
246
+ padding: 20px 0;
247
+ font-weight: normal;
248
+ font-size: 12px;
249
+ margin-bottom: 10px;
250
+ }
251
+ .container-row td.title {
252
+ overflow-wrap: break-word;
253
+ }
254
+ .container-row td {
255
+ vertical-align: top;
256
+ font-size: 14px;
257
+ padding: 5px 2px;
258
+ word-wrap: break-word;
259
+ }
260
+
261
+ body.dark .config {
262
+ color: white;
263
+ }
264
+ .config {
265
+ /*
266
+ background: rgba(0,0,0,0.9);
267
+ */
268
+ color: black;
269
+ padding: 30px;
270
+ text-align: left;
271
+ }
272
+ .config-header {
273
+ }
274
+ .config-body {
275
+ display: flex;
276
+ align-items: flex-end;
277
+ }
278
+ .config .btn {
279
+ font-size: 16px;
280
+ font-weight: bold;
281
+ width: 100px;
282
+ background: royalblue;
283
+ flex-shrink: 0;
284
+ }
285
+ .config-row {
286
+ padding: 10px 20px 0 0;
287
+ }
288
+ .label {
289
+ padding-bottom: 5px;
290
+ font-weight: bold;
291
+ }
292
+ .config-row input[type=text] {
293
+ padding: 7px;
294
+ }
295
+ .btn.save {
296
+ padding: 8px;
297
+ }
298
+ .switcher {
299
+ position: relative;
300
+ display: inline-block;
301
+ width: 60px;
302
+ height: 34px;
303
+ }
304
+
305
+ .switcher input {
306
+ opacity: 0;
307
+ width: 0;
308
+ height: 0;
309
+ }
310
+
311
+ .slider {
312
+ position: absolute;
313
+ cursor: pointer;
314
+ top: 0;
315
+ left: 0;
316
+ right: 0;
317
+ bottom: 0;
318
+ background-color: #ccc;
319
+ -webkit-transition: .4s;
320
+ transition: .4s;
321
+ }
322
+
323
+ .slider:before {
324
+ position: absolute;
325
+ content: "";
326
+ height: 26px;
327
+ width: 26px;
328
+ left: 4px;
329
+ bottom: 4px;
330
+ background-color: white;
331
+ -webkit-transition: .4s;
332
+ transition: .4s;
333
+ }
334
+
335
+ input:checked + .slider {
336
+ /*
337
+ background-color: #2196F3;
338
+ */
339
+ background-color: royalblue;
340
+ }
341
+
342
+ input:focus + .slider {
343
+ box-shadow: 0 0 1px #2196F3;
344
+ }
345
+
346
+ input:checked + .slider:before {
347
+ -webkit-transform: translateX(26px);
348
+ -ms-transform: translateX(26px);
349
+ transform: translateX(26px);
350
+ }
351
+
352
+ /* Rounded sliders */
353
+ .slider.round {
354
+ border-radius: 34px;
355
+ }
356
+
357
+ .slider.round:before {
358
+ border-radius: 50%;
359
+ }
360
+ .loading {
361
+ text-align: center;
362
+ padding: 50px;
363
+ }
364
+ .advanced a.btn {
365
+ text-align: center;
366
+ }
367
+ .advanced {
368
+ margin: 20px 0;
369
+ }
370
+ .advanced h3 {
371
+ margin: 0 0 5px;
372
+ }
373
+ .advanced .row {
374
+ display: flex;
375
+ }
376
+ .advanced input[type=text] {
377
+ flex-grow: 1;
378
+ padding: 10px;
379
+ }
380
+
381
+
382
+ @media only screen and (max-width: 480px) {
383
+ .btn2 {
384
+ padding: 5px;
385
+ font-size: 11px;
386
+ }
387
+ .nav-btns {
388
+ flex-grow: 1;
389
+ justify-content: center;
390
+ padding: 0;
391
+ }
392
+ }
393
+ </style>
394
+ <script src="/hotkeys.min.js"></script>
395
+ <script src="/common.js"></script>
396
+ <script src="/opener.js"></script>
397
+ </head>
398
+ <body class='<%=theme%>'>
399
+ <header class='navheader grabbable'>
400
+ <h1>
401
+ <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
402
+ <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
403
+ <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
404
+ <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
405
+ <a class='btn2' id='explore' href="/?mode=explore"><div><i class="fa-solid fa-globe"></i></div><div>Discover</div></a>
406
+ <a href="/network" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>Network</div></a>
407
+ <a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
408
+ <div class='flexible'></div>
409
+ <div class='nav-btns'>
410
+ <a class='btn2' href="<%=portal%>" target="_blank"><div><i class="fa-solid fa-question"></i></div><div>Help</div></a>
411
+ <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
412
+ <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
413
+ <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
414
+ <% if (agent === "electron") { %>
415
+ <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
416
+ <% } else { %>
417
+ <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
418
+ <% } %>
419
+ <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
420
+ </div>
421
+ </h1>
422
+ </header>
423
+ <main>
424
+ <div class='config'>
425
+ <div class='config-header'>
426
+ <div class='header-label'><i class='fa-solid fa-wifi'></i> Network</div>
427
+ <div class='desc'>Instant HTTPS for every app on your local network.</div>
428
+ </div>
429
+ <!--
430
+ <div class='config-body'>
431
+ <div class='config-row'>
432
+ <div class='label'>Instant HTTPS</div>
433
+ <label class="switcher">
434
+ <input id='https_active' type="checkbox" <%=https_active ? 'checked' : ''%>>
435
+ <span class="slider"></span>
436
+ </label>
437
+ </div>
438
+ </div>
439
+ -->
440
+ <div class='config-body'>
441
+ <!--
442
+ <div class='config-row'>
443
+ <div class='label'>Local Network Share</div>
444
+ <label class="switcher">
445
+ <input id='peer_active' type="checkbox" <%=peer_active ? 'checked' : ''%>>
446
+ <span class="slider"></span>
447
+ </label>
448
+ </div>
449
+ -->
450
+ <div class='config-row'>
451
+ <div id='active-label' class='label'><%=peer_active ? "On" : "Off"%></div>
452
+ <label class="switcher">
453
+ <input id='active' type="checkbox" <%=peer_active ? 'checked' : ''%>>
454
+ <span class="slider"></span>
455
+ </label>
456
+ </div>
457
+ <div class='config-row' id='network_name'>
458
+ <div class='label'>Network Name</div>
459
+ <input id='name' type='text' value="<%=name%>">
460
+ </div>
461
+ <button class='btn save'>Save</button>
462
+ </div>
463
+ <div class='advanced'>
464
+ <div class='row'>
465
+ <div id='advanced-label' class='link-label label'>Advanced</div>
466
+ <div id='reset-label' class='link-label label'>Reset HTTPS Certificates</div>
467
+ </div>
468
+ <!--
469
+ <div id='advanced-input' class='row hidden'>
470
+ <input id='git' type='text' placeholder='git url for custom network router'>
471
+ <a id="custom_download" class='btn'>Install</a>
472
+ </div>
473
+ -->
474
+ </div>
475
+ </div>
476
+ <div class='loading hidden'>
477
+ <i class="fa-solid fa-circle-notch fa-spin"></i> Stand by. Do not close this window..
478
+ </div>
479
+ <!--
480
+ <div class='header-container'>
481
+ <div class='header-label-sub'><i class="fa-solid fa-podcast"></i> Local Network</div>
482
+ <% peers.forEach((item) => { %>
483
+ <a target="_blank" href="<%=item.router%>" class='line align-top'>
484
+ <h3 class='table-grid'><%=item.name%></h3>
485
+ </a>
486
+ <% }) %>
487
+ </div>
488
+ -->
489
+ <div class='container'>
490
+ <% let brands = { win32: "windows", darwin: "apple", linux: "Linux" } %>
491
+ <% list.forEach(({ host, name, platform, processes }, index) => { %>
492
+ <div class='container-row <%=current_host === host ? 'current' : ''%>'>
493
+ <!--
494
+ <div class='header-label-sub'><i class="fa-solid fa-microchip"></i> System</div>
495
+ -->
496
+ <% if (current_host === host) { %>
497
+ <div class='header-label-sub'>
498
+ <h1><i class="fa-solid fa-podcast"></i> <%=name%> (this machine)</h1>
499
+ <div class='s'><i class="fa-brands fa-<%=brands[platform]%>"></i> <%=platform%> <%=host%></div>
500
+ </div>
501
+ <% } else { %>
502
+ <div class='header-label-sub'>
503
+ <h1><i class="fa-solid fa-wifi"></i> <%=name%></h1>
504
+ <div class='s'><i class="fa-brands fa-<%=brands[platform]%>"></i> <%=platform%> <%=host%></div>
505
+ </div>
506
+ <% } %>
507
+ <table>
508
+ <tr>
509
+ <th><h2>Server</h2><div>Running apps</div></th>
510
+ <th><h2>Shared</h2><div>Use on any machine on the network</div></th>
511
+ <th><h2>Local</h2><div>Use on <%=current_host%></div></th>
512
+ </tr>
513
+ <% processes.forEach((item) => { %>
514
+ <tr>
515
+ <td class='title'><%=item.name%></td>
516
+ <td>
517
+ <% item.external_router.forEach((domain) => { %>
518
+ <div>
519
+ <a class='ln' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
520
+ </div>
521
+ <% }) %>
522
+ <% if (item.external_ip) { %>
523
+ <div>
524
+ <a class='ln' target="_blank" href="http://<%=item.external_ip%>">http://<%=item.external_ip%></a>
525
+ </div>
526
+ <% } %>
527
+ </td>
528
+ <td>
529
+ <% item.internal_router.forEach((domain) => { %>
530
+ <div>
531
+ <a class='ln' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
532
+ </div>
533
+ <% }) %>
534
+ <div>
535
+ <a class='ln' target="_blank" href="http://localhost:<%=item.port%>">http://localhost:<%=item.port%></a>
536
+ </div>
537
+ </td>
538
+ </tr>
539
+ <% }) %>
540
+ </table>
541
+ </div>
542
+ <% }) %>
543
+ <div class='container-row hidden'>
544
+ <div class='header-label-sub'><i class="fa-solid fa-microchip"></i> System Programs</div>
545
+ <div class='line align-top'>
546
+ <h3>
547
+ <img class='icon' src="<%=icon%>">
548
+ <div class='col'>
549
+ <div class='title'>Pinokio</div>
550
+ <% if (proxy) { %>
551
+ <div class='description'><a href="<%=proxy.proxy%>" target="_blank"><%=proxy.proxy%></a> → <a href="<%=localhost%>" target="_blank"><%=localhost%></a></div>
552
+ <a class='wifi-qr badge' data-qr="<%=qr%>" data-url="<%=proxy.proxy%>"><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
553
+ <% } else { %>
554
+ <div class='description'>Share Pinokio <a href="<%=localhost%>" target="_blank"><%=localhost%></a> with other devices on the same network</div>
555
+ <% } %>
556
+ <div class='btn-container'>
557
+ <% if (proxy) { %>
558
+ <div id='wifi-stop' data-proxy="<%=proxy.proxy%>" class='btn'><div><i class="fa-solid fa-stop"></i> Stop</div></div>
559
+ <% } else { %>
560
+ <div id='wifi' class='btn'><div><i class="fa-solid fa-play"></i> Start</div></div>
561
+ <div id='wifi-starting' class='btn disabled hidden'><div><i class="fa-solid fa-circle-notch fa-spin"></i> Starting</div></div>
562
+ <% } %>
563
+ </div>
564
+ </div>
565
+ </h3>
566
+ </div>
567
+ <% items.forEach((item) => { %>
568
+ <div class='line align-top'>
569
+ <h3>
570
+ <img class='icon' src="<%=item.icon%>">
571
+ <div class='col'>
572
+ <div class='title'><%=item.name%></div>
573
+ <% if (item.proxy) { %>
574
+ <div class='description'><a href="<%=item.proxy%>" target="_blank"><%=item.proxy%></a> → <a href="<%=item.target%>" target="_blank"><%=item.target%></a></div>
575
+ <a class='wifi-qr badge' data-qr="<%=item.qr%>" data-url="<%=item.proxy%>"><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
576
+ <% } else { %>
577
+ <div class='description'>Share <%=item.target%> with other devices on the same network</div>
578
+ <% } %>
579
+ <div class='btn-container'>
580
+ <% if (item.running) { %>
581
+ <div data-port="<%=item.port%>" data-name="<%=item.name%>" data-target="<%=item.target%>" class='stop btn'><i class="fa-solid fa-stop"></i> Stop</div>
582
+ <% } else { %>
583
+ <div data-port="<%=item.port%>" data-name="<%=item.name%>" data-target="<%=item.target%>" class='start btn'><i class="fa-solid fa-play"></i> Start at port <%=item.port%></div>
584
+ <% } %>
585
+ </div>
586
+ </div>
587
+ </h3>
588
+ </div>
589
+ <% }) %>
590
+ </div>
591
+ <!--
592
+ <div class='container-row'>
593
+ <div class='header-label-sub'><i class="fa-solid fa-dice-d6"></i> Pinokio</div>
594
+ <% apps.forEach((item) => { %>
595
+ <a class='line align-top' href="<%=item.link%>">
596
+ <h3>
597
+ <% if (item.icon) { %>
598
+ <img class='icon' src="<%=item.icon%>">
599
+ <% } else { %>
600
+ <% if (theme === 'dark') { %>
601
+ <img class='icon' src="/pinokio-white.png">
602
+ <% } else { %>
603
+ <img class='icon' src="/pinokio-black.png">
604
+ <% } %>
605
+ <% } %>
606
+ <div class='col'>
607
+ <div class='title'><%=item.name%></div>
608
+ <div class='description'><%=item.description%></div>
609
+ </div>
610
+ <div class='spinner'>
611
+ <i class="fa-solid fa-chevron-right"></i>
612
+ </div>
613
+ </h3>
614
+ </a>
615
+ <% }) %>
616
+ </div>
617
+ -->
618
+ </div>
619
+ </main>
620
+ <script>
621
+ document.querySelector("#reset-label").addEventListener("click", async (e) => {
622
+ e.preventDefault()
623
+ e.stopPropagation()
624
+ let ok = confirm("are you sure you want to re-generate http certificates?")
625
+ if (ok) {
626
+ let r = await fetch("/network/reset", {
627
+ method: "post",
628
+ headers: {
629
+ "Content-Type": "application/json"
630
+ }
631
+ }).then((res) => {
632
+ return res.json()
633
+ })
634
+ if (r.success) {
635
+ //alert("Successfully updated the pinokio home to " + val)
636
+ document.querySelector(".loading").classList.remove("hidden")
637
+ document.querySelector(".save").classList.add("hidden")
638
+ fetch("/restart", {
639
+ method: "post"
640
+ }, () => {
641
+ })
642
+ setInterval(async () => {
643
+ try {
644
+ let res = await fetch("/check_peer").then((res) => {
645
+ return res.json()
646
+ })
647
+ if (res.success) {
648
+ document.querySelector(".loading").classList.add("hidden")
649
+ location.href = location.href
650
+ }
651
+ } catch (e) {
652
+ console.log(e)
653
+ }
654
+ }, 1000)
655
+ } else if (r.error) {
656
+ alert(r.error)
657
+ location.href = location.href
658
+ }
659
+ }
660
+
661
+ })
662
+ document.querySelector("#advanced-label").addEventListener("click", (e) => {
663
+ e.preventDefault()
664
+ e.stopPropagation()
665
+ //document.querySelector("#advanced-input").classList.toggle("hidden")
666
+ Commander({
667
+ callback: "/network",
668
+ path: "~/network",
669
+ icon: "fa-solid fa-circle-down",
670
+ title: "Custom Router",
671
+ placeholder: "enter a custom router git url",
672
+ description: `<div>you can write your own custom routers to handle custom request handling for any port <a target="_blank" href="<%=docs%>">Learn more</a></div>`,
673
+ message: (url) => {
674
+ let name = new URL(url).pathname.split("/").slice(-2).join("_")
675
+ return encodeURIComponent(`git clone ${url} ${name}`)
676
+ }
677
+ })
678
+ })
679
+ if (document.querySelector("#active").checked) {
680
+ console.log("checked")
681
+ document.querySelector("#network_name").classList.remove("hidden")
682
+ } else {
683
+ console.log("not checked")
684
+ document.querySelector("#network_name").classList.add("hidden")
685
+ }
686
+ document.querySelector("#active").addEventListener("change", (e)=> {
687
+ console.log(e.target.checked)
688
+ if (e.target.checked) {
689
+ document.querySelector("#network_name").classList.remove("hidden")
690
+ document.querySelector("#active-label").innerHTML = "On"
691
+ } else {
692
+ document.querySelector("#network_name").classList.add("hidden")
693
+ document.querySelector("#active-label").innerHTML = "Off"
694
+ }
695
+ })
696
+ document.querySelector("main").addEventListener("click", async (e) => {
697
+ let target
698
+
699
+ if (e.target.classList.contains("save")) {
700
+ target = e.target
701
+ } else {
702
+ target = e.target.closest(".save")
703
+ }
704
+
705
+ if (target) {
706
+ let active = document.querySelector("#active").checked ? "1": "0"
707
+ let body = {
708
+ PINOKIO_NETWORK_NAME: document.querySelector("#name").value,
709
+ PINOKIO_NETWORK_ACTIVE: active,
710
+ PINOKIO_HTTPS_ACTIVE: active,
711
+ }
712
+ /*
713
+ let body = {
714
+ PINOKIO_NETWORK_NAME: document.querySelector("#name").value,
715
+ PINOKIO_NETWORK_ACTIVE: (document.querySelector("#peer_active").checked ? "1": "0"),
716
+ PINOKIO_HTTPS_ACTIVE: (document.querySelector("#https_active").checked ? "1": "0")
717
+ }
718
+ */
719
+ console.log(body)
720
+ let r = await fetch("/network", {
721
+ method: "post",
722
+ headers: { "Content-Type": "application/json" },
723
+ body: JSON.stringify(body)
724
+ }).then((res) => {
725
+ return res.json()
726
+ })
727
+ if (r.success) {
728
+ //alert("Successfully updated the pinokio home to " + val)
729
+ document.querySelector(".loading").classList.remove("hidden")
730
+ document.querySelector(".save").classList.add("hidden")
731
+ fetch("/restart", {
732
+ method: "post"
733
+ }, () => {
734
+ })
735
+ setInterval(async () => {
736
+ try {
737
+ let res = await fetch("/check_peer").then((res) => {
738
+ return res.json()
739
+ })
740
+ if (res.success) {
741
+ document.querySelector(".loading").classList.add("hidden")
742
+ location.href = location.href
743
+ }
744
+ } catch (e) {
745
+ console.log(e)
746
+ }
747
+ }, 1000)
748
+ } else if (r.error) {
749
+ alert(r.error)
750
+ location.href = location.href
751
+ }
752
+ return
753
+ }
754
+
755
+ if (e.target.classList.contains("stop")) {
756
+ target = e.target
757
+ } else {
758
+ target = e.target.closest(".stop")
759
+ }
760
+ if (target) {
761
+ // stop
762
+ let res = await fetch("/proxy", {
763
+ method: "post",
764
+ headers: {
765
+ "Content-Type": "application/json"
766
+ },
767
+ body: JSON.stringify({
768
+ action: "stop",
769
+ target: target.getAttribute("data-target"),
770
+ name: target.getAttribute("data-name")
771
+ })
772
+ }).then((res) => {
773
+ return res.json()
774
+ })
775
+ location.href = location.href
776
+ return
777
+ }
778
+
779
+ if (e.target.classList.contains("start")) {
780
+ target = e.target
781
+ } else {
782
+ target = e.target.closest(".start")
783
+ }
784
+ if (target) {
785
+ let res = await fetch("/proxy", {
786
+ method: "post",
787
+ headers: {
788
+ "Content-Type": "application/json"
789
+ },
790
+ body: JSON.stringify({
791
+ action: "start",
792
+ target: target.getAttribute("data-target"),
793
+ name: target.getAttribute("data-name"),
794
+ port: target.getAttribute("data-port")
795
+ })
796
+ }).then((res) => {
797
+ return res.json()
798
+ })
799
+ location.href = location.href
800
+ }
801
+
802
+ if (e.target.classList.contains("wifi-qr")) {
803
+ target = e.target
804
+ } else {
805
+ target = e.target.closest(".wifi-qr")
806
+ }
807
+ if (target) {
808
+ let url = target.getAttribute("data-url")
809
+ let qr = target.getAttribute("data-qr")
810
+ console.log({ url, qr })
811
+ await Swal.fire({
812
+ title: "Local Share",
813
+ customClass: {
814
+ popup: "min-popup",
815
+ title: "min-title"
816
+ },
817
+ showConfirmButton: false,
818
+ html: `<div class='min-modal'>
819
+ <div>Access Pinokio from</div>
820
+ <div>any local network device</div>
821
+ <div><img src="${qr}"></div>
822
+ <a href="${url}" target="_blank">${url}</a>
823
+ </div>`
824
+ })
825
+ }
826
+
827
+
828
+ })
829
+ if (document.querySelector("#back")) {
830
+ document.querySelector("#back").addEventListener("click", (e) => {
831
+ history.back()
832
+ })
833
+ }
834
+ if (document.querySelector("#forward")) {
835
+ document.querySelector("#forward").addEventListener("click", (e) => {
836
+ history.forward()
837
+ })
838
+ }
839
+ <% if (proxy) { %>
840
+ if (document.querySelector("#wifi-stop")) {
841
+ document.querySelector("#wifi-stop").addEventListener("click", async (e) => {
842
+ let res = await fetch("/unpublish", {
843
+ method: "post",
844
+ headers: {
845
+ "Content-Type": "application/json"
846
+ },
847
+ body: JSON.stringify({
848
+ type: "local"
849
+ })
850
+ }).then((res) => {
851
+ return res.json()
852
+ })
853
+ console.log(res)
854
+ location.href = location.href
855
+ })
856
+ }
857
+ <% } else { %>
858
+ if (document.querySelector("#wifi")) {
859
+ document.querySelector("#wifi").addEventListener("click", async (e) => {
860
+ document.querySelector("#wifi").classList.add("hidden")
861
+ document.querySelector("#wifi-starting").classList.remove("hidden")
862
+ let res = await fetch("/publish", {
863
+ method: "post",
864
+ headers: {
865
+ "Content-Type": "application/json"
866
+ },
867
+ body: JSON.stringify({
868
+ type: "local"
869
+ })
870
+ }).then((res) => {
871
+ return res.json()
872
+ })
873
+ console.log(res)
874
+ location.href = location.href
875
+ })
876
+ }
877
+ <% } %>
878
+ setInterval(() => {
879
+ fetch("/peer_check").then((res) => {
880
+ return res.json()
881
+ }).then((res) => {
882
+ if (res.updated) {
883
+ location.href = location.href
884
+ }
885
+ })
886
+ }, 2000)
887
+ </script>
888
+ </body>
889
+ </html>