diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..339cb8a47 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "submodules/v86"] + path = submodules/v86 + url = git@github.com:copy/v86.git diff --git a/doc/i18n/README.hy.md b/doc/i18n/README.hy.md new file mode 100644 index 000000000..b3542cf42 --- /dev/null +++ b/doc/i18n/README.hy.md @@ -0,0 +1,131 @@ +

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

+ +

Ինտերնետ ՕՀ! Անվճար, բաց կոդով և ինքնահոսթ հնարավորությամբ։

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « Օնլայն դեմո » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter-ը առաջադեմ, բաց կոդով ինտերնետային օպերացիոն համակարգ է, որը նախագծված է լինել ֆունկցիոնալ հարուստ, բացառիկ արագ և բարձր ընդլայնելի։ Puter-ը կարող է օգտագործվել հետևյալ կերպ․ + +- Անձնական ամպային համակարգ՝ առաջնային գաղտնիությամբ, որը թույլ է տալիս պահել ձեր բոլոր ֆայլերը, հավելվածները և խաղերը մեկ անվտանգ վայրում, որը հասանելի է ցանկացած վայրից և ցանկացած ժամանակ։ +- Պլատֆորմ կայքերի, վեբ հավելվածների և խաղերի ստեղծման և հրապարակման համար։ +- Dropbox, Google Drive, OneDrive և այլ ծառայությունների այլընտրանք՝ նոր ինտերֆեյսով և հզոր գործառույթներով։ +- Հեռավոր աշխատասեղանի միջավայր սերվերների և աշխատանքային կայանների համար։ +- Պարզ, բաց կոդով նախագիծ և համայնք՝ վեբ ծրագրավորման, ամպային հաշվարկների, բաշխված համակարգերի և այլ թեմաների մասին սովորելու համար։ + +
+ +## Սկսել + + +### 💻 Լոկալ ծրագրավորում + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Սա կգործակի Puter-ը հետևյալ հասցեով՝ http://puter.localhost:4100 (կամ հաջորդ հասանելի պորտով)։ + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter-ը հասանելի է որպես հյուրընկալվող ծառայություն [**puter.com**](https://puter.com). + +
+ +## System Requirements + +- **Օպերացիոն համակարգ:** Linux, macOS, Windows +- **Օպերատիվ հիշողություն:** 2GB նվազագույնը (4GB խորհուրդ է տրվում) +- **Համակարգչի հիշողություն:** 1GB ազատ տարածություն +- **Node.js:** Տարբերակ 16+ (Տարբերակ 22+ խորհուրդ է տրվում) +- **npm:** Վերջին կայուն տարբերակը + +
+ +## Աջակցություն + +Կապվեք համակարգողների և համայնքի հետ այս կայքերի միջոցով՝ + +- Սխալների կամ գործառույթի հարցում՝ (https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Անվտանգության խնդիրներ՝ [security@puter.com](mailto:security@puter.com) +- Email maintainers at [hi@puter.com](mailto:hi@puter.com) + +Մենք միշտ ուրախ ենք օգնել ձեզ ցանկացած հարցում։ Մի կաշկանդվեք հարցնել։ + +
+ + +## Լիցենզիա + +Այս պահոցարանը, ներառյալ բոլոր իր բովանդակությունը, ենթա-պրոյեկտները, մոդուլները և բաղադրիչները, լիցենզավորվում են [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) լիցենզիայի տակ, եթե այլ կերպ հստակ նշված չէ։ Այս պահոցարանում ներառված երրորդ կողմի գրադարանները կարող են ենթարկվել իրենց սեփական լիցենզիաներին։ + +
diff --git a/package-lock.json b/package-lock.json index 16947f4cb..a28ed1a78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6897,6 +6897,13 @@ "@types/node": "*" } }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/http-assert": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.5.tgz", @@ -8194,6 +8201,17 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, "node_modules/camelcase": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", @@ -9189,6 +9207,16 @@ "node": ">=8" } }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -9249,6 +9277,17 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/dotenv": { "version": "16.4.5", "dev": true, @@ -9286,6 +9325,10 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, + "node_modules/emulator": { + "resolved": "src/emulator", + "link": true + }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", @@ -10800,6 +10843,147 @@ "dev": true, "license": "MIT" }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/htmlparser2/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/htmlparser2/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -12279,6 +12463,16 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -12825,6 +13019,17 @@ "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", "license": "MIT" }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-abi": { "version": "3.65.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", @@ -13399,6 +13604,17 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "license": "(MIT AND Zlib)" }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -13460,6 +13676,17 @@ "node": ">= 0.8" } }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -13806,6 +14033,17 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -14152,6 +14390,16 @@ "dev": true, "license": "MIT" }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -14165,6 +14413,93 @@ "node": ">=4" } }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -15822,6 +16157,13 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true, + "license": "MIT" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -16762,6 +17104,13 @@ "mocha": "^10.2.0" } }, + "src/emulator": { + "version": "1.0.0", + "license": "AGPL-3.0-only", + "devDependencies": { + "html-webpack-plugin": "^5.6.0" + } + }, "src/git": { "version": "1.0.0", "license": "AGPL-3.0-only", diff --git a/src/backend/src/modules/selfhosted/SelfHostedModule.js b/src/backend/src/modules/selfhosted/SelfHostedModule.js index 9bbd3523c..6ec4b6e2b 100644 --- a/src/backend/src/modules/selfhosted/SelfHostedModule.js +++ b/src/backend/src/modules/selfhosted/SelfHostedModule.js @@ -81,6 +81,12 @@ class SelfHostedModule extends AdvancedBase { PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js', } }, + { + name: 'emulator:webpack-watch', + directory: 'src/emulator', + command: 'npm', + args: ['run', 'start-webpack'], + }, ], }); @@ -107,6 +113,18 @@ class SelfHostedModule extends AdvancedBase { prefix: '/builtin/dev-center', path: path_.resolve(__dirname, RELATIVE_PATH, 'src/dev-center'), }, + { + prefix: '/builtin/dev-center', + path: path_.resolve(__dirname, RELATIVE_PATH, 'src/dev-center'), + }, + { + prefix: '/builtin/emulator', + path: path_.resolve(__dirname, RELATIVE_PATH, 'src/emulator/dist'), + }, + { + prefix: '/vendor/v86', + path: path_.resolve(__dirname, RELATIVE_PATH, 'submodules/v86/build'), + }, ], }); diff --git a/src/emulator/assets/template.html b/src/emulator/assets/template.html new file mode 100644 index 000000000..87721584d --- /dev/null +++ b/src/emulator/assets/template.html @@ -0,0 +1,45 @@ + + + + <%= htmlWebpackPlugin.options.title || 'Webpack App'%> + + <% if (htmlWebpackPlugin.files.favicon) { %> + + <% } %> + <% if (htmlWebpackPlugin.options.mobile) { %> + + <% } %> + + <% for (var css in htmlWebpackPlugin.files.css) { %> + + <% } %> + + + + + + +<% if (htmlWebpackPlugin.options.appMountId) { %> +
+<% } %> + +<% if (htmlWebpackPlugin.options.appMountIds && htmlWebpackPlugin.options.appMountIds.length > 0) { %> +<% for (var index in htmlWebpackPlugin.options.appMountIds) { %> +
+<% } %> +<% } %> + +<% if (htmlWebpackPlugin.options.window) { %> + +<% } %> + +<% for (var chunk in htmlWebpackPlugin.files.chunks) { %> + +<% } %> + + + \ No newline at end of file diff --git a/src/emulator/package.json b/src/emulator/package.json new file mode 100644 index 000000000..3879a4727 --- /dev/null +++ b/src/emulator/package.json @@ -0,0 +1,16 @@ +{ + "name": "emulator", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start-webpack": "webpack --watch --devtool source-map" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "description": "", + "devDependencies": { + "html-webpack-plugin": "^5.6.0" + } +} diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js new file mode 100644 index 000000000..e4d8630c1 --- /dev/null +++ b/src/emulator/src/main.js @@ -0,0 +1 @@ +puter.ui.launchApp('editor'); diff --git a/src/emulator/webpack.config.js b/src/emulator/webpack.config.js new file mode 100644 index 000000000..6983e59a3 --- /dev/null +++ b/src/emulator/webpack.config.js @@ -0,0 +1,12 @@ +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + entry: [ + './src/main.js' + ], + plugins: [ + new HtmlWebpackPlugin({ + template: 'assets/template.html' + }), + ] +}; diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/services/ExecService.js index 2146f758d..15ef144cf 100644 --- a/src/gui/src/services/ExecService.js +++ b/src/gui/src/services/ExecService.js @@ -51,8 +51,8 @@ export class ExecService extends Service { // If `window-active` is set (meanign the window is focused), focus the window one more time // this is to ensure that the iframe is `definitely` focused and can receive keyboard events (e.g. keydown) - if(child_process.el_win.hasClass('window-active')){ - child_process.el_win.focusWindow(); + if($(child_process.references.el_win).hasClass('window-active')){ + $(child_process.references.el_win).focusWindow(); } }); diff --git a/src/gui/utils.js b/src/gui/utils.js index 1e11e40d9..389454b64 100644 --- a/src/gui/utils.js +++ b/src/gui/utils.js @@ -129,11 +129,11 @@ async function build(options){ for(let i = 0; i < js_paths.length; i++){ main_array.push(path.join(__dirname, 'src', js_paths[i])); } - webpack({ - ...BaseConfig({ + await webpack({ + ...(await BaseConfig({ ...options, env: 'prod', - }), + })), mode: 'production', optimization: { minimize: true, diff --git a/src/gui/webpack.config.cjs b/src/gui/webpack.config.cjs index 3c1c4fed8..b69b9c06d 100644 --- a/src/gui/webpack.config.cjs +++ b/src/gui/webpack.config.cjs @@ -1,8 +1,8 @@ const BaseConfig = require('./webpack/BaseConfig.cjs'); -module.exports = { - ...BaseConfig({ env: 'dev' }), +module.exports = async () => ({ + ...(await BaseConfig({ env: 'dev' })), optimization: { minimize: false }, -}; +}); diff --git a/src/gui/webpack/BaseConfig.cjs b/src/gui/webpack/BaseConfig.cjs index 9e0d63658..7c736b350 100644 --- a/src/gui/webpack/BaseConfig.cjs +++ b/src/gui/webpack/BaseConfig.cjs @@ -1,6 +1,6 @@ const path = require('path'); const EmitPlugin = require('./EmitPlugin.cjs'); -module.exports = (options = {}) => { +module.exports = async (options = {}) => { const config = {}; config.entry = [ './src/init_sync.js', @@ -18,7 +18,7 @@ module.exports = (options = {}) => { filename: 'bundle.min.js', }; config.plugins = [ - EmitPlugin({ + await EmitPlugin({ options, dir: path.join(__dirname, '../src/icons'), }), diff --git a/src/gui/webpack/EmitPlugin.cjs b/src/gui/webpack/EmitPlugin.cjs index d631abc1f..9e4fd6ded 100644 --- a/src/gui/webpack/EmitPlugin.cjs +++ b/src/gui/webpack/EmitPlugin.cjs @@ -1,78 +1,80 @@ const fs = require('fs'); const path = require('path'); const uglifyjs = require('uglify-js'); +const webpack = require('webpack'); -module.exports = ({ dir, options }) => function () { - const compiler = this; - compiler.hooks.emit.tapAsync('EmitPlugin', async (compilation, callback) => { - let prefix_text = ''; - prefix_text += `window.gui_env="${options.env}";\n`; +module.exports = async ({ dir, options }) => { + let prefix_text = ''; + prefix_text += `window.gui_env="${options.env}";\n`; - // ----------------------------------------------- - // Combine all images into a single js file - // ----------------------------------------------- - { - let icons = 'window.icons = [];\n'; - fs.readdirSync(dir).forEach(file => { - // skip dotfiles - if (file.startsWith('.')) - return; - // load image - let buff = new Buffer.from(fs.readFileSync(dir + '/' + file)); - // convert to base64 - let base64data = buff.toString('base64'); - // add to `window.icons` - if (file.endsWith('.png')) - icons += `window.icons['${file}'] = "data:image/png;base64,${base64data}";\n`; - else if (file.endsWith('.svg')) - icons += `window.icons['${file}'] = "data:image/svg+xml;base64,${base64data}";\n`; - }); - prefix_text += icons + '\n'; - } + // ----------------------------------------------- + // Combine all images into a single js file + // ----------------------------------------------- + { + let icons = 'window.icons = [];\n'; + fs.readdirSync(dir).forEach(file => { + // skip dotfiles + if (file.startsWith('.')) + return; + // load image + let buff = new Buffer.from(fs.readFileSync(dir + '/' + file)); + // convert to base64 + let base64data = buff.toString('base64'); + // add to `window.icons` + if (file.endsWith('.png')) + icons += `window.icons['${file}'] = "data:image/png;base64,${base64data}";\n`; + else if (file.endsWith('.svg')) + icons += `window.icons['${file}'] = "data:image/svg+xml;base64,${base64data}";\n`; + }); + prefix_text += icons + '\n'; + } - // ----------------------------------------------- - // Concat/merge the JS libraries and save them to ./dist/libs.js - // ----------------------------------------------- - { - const lib_paths = require('./libPaths.cjs'); - let js = ''; - for(let i = 0; i < lib_paths.length; i++){ - const file = path.join(__dirname, '../src/lib/', lib_paths[i]); - // js - if(file.endsWith('.js') && !file.endsWith('.min.js')){ - let minified_code = await uglifyjs.minify(fs.readFileSync(file).toString(), {mangle: false}); - if(minified_code && minified_code.code){ - js += minified_code.code; - if(options?.verbose) - console.log('minified: ', file); - } - }else{ - js += fs.readFileSync(file); + // ----------------------------------------------- + // Concat/merge the JS libraries and save them to ./dist/libs.js + // ----------------------------------------------- + { + const lib_paths = require('./libPaths.cjs'); + let js = ''; + for(let i = 0; i < lib_paths.length; i++){ + const file = path.join(__dirname, '../src/lib/', lib_paths[i]); + // js + if(file.endsWith('.js') && !file.endsWith('.min.js')){ + let minified_code = await uglifyjs.minify(fs.readFileSync(file).toString(), {mangle: false}); + if(minified_code && minified_code.code){ + js += minified_code.code; if(options?.verbose) - console.log('skipped minification: ', file); + console.log('minified: ', file); } - - js += '\n\n\n'; + }else{ + js += fs.readFileSync(file); + if(options?.verbose) + console.log('skipped minification: ', file); } - prefix_text += js; + + js += '\n\n\n'; } + prefix_text += js; + } + + return new webpack.BannerPlugin({ + banner: prefix_text, + raw: true, + }); - // ----------------------------------------------- - // Webpack understands this code better than I do - // ----------------------------------------------- - Object.keys(compilation.assets).forEach((assetName) => { - if (assetName.endsWith('.js')) { - const asset = compilation.assets[assetName]; - const originalSource = asset.source(); - const newSource = `${prefix_text}\n${originalSource}`; - compilation.assets[assetName] = { - source: () => newSource, - size: () => newSource.length, - }; - } - }); + // ----------------------------------------------- + // Webpack understands this code better than I do + // ----------------------------------------------- + // Object.keys(compilation.assets).forEach((assetName) => { + // if (assetName.endsWith('.js')) { + // const asset = compilation.assets[assetName]; + // const originalSource = asset.source(); + // const newSource = `${prefix_text}\n${originalSource}`; + // compilation.assets[assetName] = { + // source: () => newSource, + // size: () => newSource.length, + // }; + // } + // }); - console.log('END'); - callback(); - }); + console.log('END'); }; diff --git a/submodules/v86 b/submodules/v86 new file mode 160000 index 000000000..f3339aa78 --- /dev/null +++ b/submodules/v86 @@ -0,0 +1 @@ +Subproject commit f3339aa78eeb9221d24ff86a2ea74b9ee1d2ee90