Skip to content

Commit fa42b08

Browse files
committed
Initial commit
0 parents  commit fa42b08

File tree

290 files changed

+99553
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

290 files changed

+99553
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.DS_Store
2+
node_modules/
3+
*.zip
4+
*.tgz
5+
license.config.json

LICENSE.txt

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 78 additions & 0 deletions

build.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const {build} = require("./utils.js")
2+
3+
build();

dev-server.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const express = require("express");
2+
const { generateDevHtml, build } = require("./utils.js");
3+
const { argv } = require('node:process');
4+
const chalk = require('chalk');
5+
6+
const app = express();
7+
let port = 4000; // Starting port
8+
const maxAttempts = 10; // Maximum number of ports to try
9+
const env = argv[2] ?? "dev";
10+
11+
const startServer = (attempt) => {
12+
if (attempt > maxAttempts) {
13+
console.error(chalk.red(`ERROR: Unable to find an available port after ${maxAttempts} attempts.`));
14+
return;
15+
}
16+
17+
app.listen(port, () => {
18+
console.log("\n-----------------------------------------------------------\n");
19+
console.log(`Puter is now live at: `, chalk.underline.blue(`http://localhost:${port}`));
20+
console.log("\n-----------------------------------------------------------\n");
21+
}).on('error', (err) => {
22+
if (err.code === 'EADDRINUSE') { // Check if the error is because the port is already in use
23+
console.error(chalk.red(`ERROR: Port ${port} is already in use. Trying next port...`));
24+
port++; // Increment the port number
25+
startServer(attempt + 1); // Try the next port
26+
}
27+
});
28+
};
29+
30+
// Start the server with the first attempt
31+
startServer(1);
32+
33+
// build the GUI
34+
build();
35+
36+
app.get(["/", "/app/*", "/action/*"], (req, res) => {
37+
res.send(generateDevHtml({
38+
env: env,
39+
api_origin: "https://api.puter.com",
40+
title: "Puter",
41+
max_item_name_length: 150,
42+
require_email_verification_to_publish_website: false,
43+
short_description: `Puter is a privacy-first personal cloud that houses all your files, apps, and games in one private and secure place, accessible from anywhere at any time.`,
44+
}));
45+
})
46+
app.use(express.static('./'));
47+
48+
if(env === "prod"){
49+
// make sure to serve the ./dist/ folder maps to the root of the website
50+
app.use(express.static('./dist/'));
51+
}
52+
53+
if(env === "dev"){
54+
app.use(express.static('./src/'));
55+
}
56+
57+
module.exports = app;

dist/browserconfig.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<browserconfig>
3+
<msapplication>
4+
<tile>
5+
<square70x70logo src="./favicons/ms-icon-70x70.png"/>
6+
<square150x150logo src="./favicons/ms-icon-150x150.png"/>
7+
<square310x310logo src="./favicons/ms-icon-310x310.png"/>
8+
<TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>

dist/bundle.min.css

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/bundle.min.js

Lines changed: 323 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/favicon.ico

1.12 KB
Binary file not shown.
9.49 KB
13 KB

dist/favicons/android-icon-36x36.png

2.12 KB

dist/favicons/android-icon-48x48.png

2.83 KB

dist/favicons/android-icon-72x72.png

4.29 KB

dist/favicons/android-icon-96x96.png

5.68 KB

dist/favicons/apple-icon-114x114.png

6.82 KB

dist/favicons/apple-icon-120x120.png

7.25 KB

dist/favicons/apple-icon-144x144.png

9.49 KB

dist/favicons/apple-icon-152x152.png

10.3 KB

dist/favicons/apple-icon-180x180.png

13.3 KB

dist/favicons/apple-icon-57x57.png

3.34 KB

dist/favicons/apple-icon-60x60.png

3.51 KB

dist/favicons/apple-icon-72x72.png

4.29 KB

dist/favicons/apple-icon-76x76.png

4.46 KB
13.5 KB

dist/favicons/apple-icon.png

13.5 KB

dist/favicons/browserconfig.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>

dist/favicons/favicon-16x16.png

1.1 KB

dist/favicons/favicon-32x32.png

1.92 KB

dist/favicons/favicon-96x96.png

5.68 KB

dist/favicons/favicon.ico

1.12 KB
Binary file not shown.

dist/favicons/manifest.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "App",
3+
"icons": [
4+
{
5+
"src": "\/android-icon-36x36.png",
6+
"sizes": "36x36",
7+
"type": "image\/png",
8+
"density": "0.75"
9+
},
10+
{
11+
"src": "\/android-icon-48x48.png",
12+
"sizes": "48x48",
13+
"type": "image\/png",
14+
"density": "1.0"
15+
},
16+
{
17+
"src": "\/android-icon-72x72.png",
18+
"sizes": "72x72",
19+
"type": "image\/png",
20+
"density": "1.5"
21+
},
22+
{
23+
"src": "\/android-icon-96x96.png",
24+
"sizes": "96x96",
25+
"type": "image\/png",
26+
"density": "2.0"
27+
},
28+
{
29+
"src": "\/android-icon-144x144.png",
30+
"sizes": "144x144",
31+
"type": "image\/png",
32+
"density": "3.0"
33+
},
34+
{
35+
"src": "\/android-icon-192x192.png",
36+
"sizes": "192x192",
37+
"type": "image\/png",
38+
"density": "4.0"
39+
}
40+
]
41+
}

dist/favicons/ms-icon-144x144.png

9.49 KB

dist/favicons/ms-icon-150x150.png

10.1 KB

dist/favicons/ms-icon-310x310.png

31.1 KB

dist/favicons/ms-icon-70x70.png

4.16 KB

dist/gui.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
window.gui_env="prod";
2+
3+
window.puter_gui_enabled = true;
4+
/**
5+
* Initializes and configures the GUI (Graphical User Interface) settings based on the provided options.
6+
*
7+
* The function sets global variables in the window object for various settings such as origins and domain names.
8+
* It also handles loading different resources depending on the environment (development or production).
9+
*
10+
* @param {Object} options - Configuration options to initialize the GUI.
11+
* @param {string} [options.gui_origin='https://puter.com'] - The origin URL for the GUI.
12+
* @param {string} [options.api_origin='https://api.puter.com'] - The origin URL for the API.
13+
* @param {number} [options.max_item_name_length=500] - Maximum allowed length for an item name.
14+
* @param {boolean} [options.require_email_verification_to_publish_website=true] - Flag to decide whether email verification is required to publish a website.
15+
*
16+
* @property {string} [options.app_domain] - Extracted domain name from gui_origin. It's derived automatically if not provided.
17+
* @property {string} [window.gui_env] - The environment in which the GUI is running (e.g., "dev" or "prod").
18+
*
19+
* @returns {Promise<void>} Returns a promise that resolves when initialization and resource loading are complete.
20+
*
21+
* @example
22+
* window.gui({
23+
* gui_origin: 'https://myapp.com',
24+
* api_origin: 'https://myapi.com',
25+
* max_item_name_length: 250
26+
* });
27+
*/
28+
29+
window.gui = async function(options){
30+
options = options ?? {};
31+
// app_origin is deprecated, use gui_origin instead
32+
window.gui_origin = options.gui_origin ?? options.app_origin ?? `https://puter.com`;
33+
window.app_domain = options.app_domain ?? new URL(window.gui_origin).hostname;
34+
window.hosting_domain = options.hosting_domain ?? 'puter.site';
35+
window.api_origin = options.api_origin ?? "https://api.puter.com";
36+
window.max_item_name_length = options.max_item_name_length ?? 500;
37+
window.require_email_verification_to_publish_website = options.require_email_verification_to_publish_website ?? true;
38+
39+
// Add Puter.JS
40+
await loadScript('https://js.puter.com/v2/');
41+
42+
// DEV: Load the initgui.js file if we are in development mode
43+
if(!window.gui_env || window.gui_env === "dev"){
44+
await loadScript('/initgui.js', {isModule: true});
45+
}
46+
47+
// PROD: load the minified bundles if we are in production mode
48+
// note: the order of the bundles is important
49+
// note: Build script will prepend `window.gui_env="prod"` to the top of the file
50+
else if(gui_env === "prod"){
51+
// Load the minified bundles
52+
await loadCSS('/dist/bundle.min.css');
53+
await loadScript('/dist/bundle.min.js');
54+
}
55+
56+
// 🚀 Launch the GUI 🚀
57+
initgui();
58+
}
59+
60+
/**
61+
* Dynamically loads an external JavaScript file.
62+
* @param {string} url The URL of the external script to load.
63+
* @param {Object} [options] Optional configuration for the script.
64+
* @param {boolean} [options.isModule] Whether the script is a module.
65+
* @param {boolean} [options.defer] Whether the script should be deferred.
66+
* @param {Object} [options.dataAttributes] An object containing data attributes to add to the script element.
67+
* @returns {Promise} A promise that resolves once the script has loaded, or rejects on error.
68+
*/
69+
window.loadScript = async function(url, options = {}) {
70+
return new Promise((resolve, reject) => {
71+
const script = document.createElement('script');
72+
script.src = url;
73+
74+
// Set default script loading behavior
75+
script.async = true;
76+
77+
// Handle if it is a module
78+
if (options.isModule) {
79+
script.type = 'module';
80+
}
81+
82+
// Handle defer attribute
83+
if (options.defer) {
84+
script.defer = true;
85+
script.async = false; // When "defer" is true, "async" should be false as they are mutually exclusive
86+
}
87+
88+
// Add arbitrary data attributes
89+
if (options.dataAttributes && typeof options.dataAttributes === 'object') {
90+
for (const [key, value] of Object.entries(options.dataAttributes)) {
91+
script.setAttribute(`data-${key}`, value);
92+
}
93+
}
94+
95+
// Resolve the promise when the script is loaded
96+
script.onload = () => resolve();
97+
98+
// Reject the promise if there's an error during load
99+
script.onerror = (error) => reject(new Error(`Failed to load script at url: ${url}`));
100+
101+
// Append the script to the body
102+
document.body.appendChild(script);
103+
});
104+
};
105+
106+
/**
107+
* Dynamically loads an external CSS file.
108+
* @param {string} url The URL of the external CSS to load.
109+
* @returns {Promise} A promise that resolves once the CSS has loaded, or rejects on error.
110+
*/
111+
window.loadCSS = async function(url) {
112+
return new Promise((resolve, reject) => {
113+
const link = document.createElement('link');
114+
link.rel = 'stylesheet';
115+
link.href = url;
116+
117+
link.onload = () => {
118+
resolve();
119+
};
120+
121+
link.onerror = (error) => {
122+
reject(new Error(`Failed to load CSS at url: ${url}`));
123+
};
124+
125+
document.head.appendChild(link);
126+
});
127+
}

dist/images/screenshot.png

1.57 MB

dist/images/wallpaper.webp

175 KB
Binary file not shown.

dist/manifest.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "App",
3+
"icons": [
4+
{
5+
"src": "/favicons/android-icon-36x36.png",
6+
"sizes": "36x36",
7+
"type": "image/png",
8+
"density": "0.75"
9+
},
10+
{
11+
"src": "/favicons/android-icon-48x48.png",
12+
"sizes": "48x48",
13+
"type": "image/png",
14+
"density": "1.0"
15+
},
16+
{
17+
"src": "/favicons/android-icon-72x72.png",
18+
"sizes": "72x72",
19+
"type": "image/png",
20+
"density": "1.5"
21+
},
22+
{
23+
"src": "/favicons/android-icon-96x96.png",
24+
"sizes": "96x96",
25+
"type": "image/png",
26+
"density": "2.0"
27+
},
28+
{
29+
"src": "/favicons/android-icon-144x144.png",
30+
"sizes": "144x144",
31+
"type": "image/png",
32+
"density": "3.0"
33+
},
34+
{
35+
"src": "/favicons/android-icon-192x192.png",
36+
"sizes": "192x192",
37+
"type": "image/png",
38+
"density": "4.0"
39+
}
40+
]
41+
}

0 commit comments

Comments
 (0)