Merge branch 'HeyPuter:main' into main

This commit is contained in:
Muhammad Fauzi 2024-08-31 23:46:25 +07:00 committed by GitHub
commit 3acabc6c79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
128 changed files with 3011 additions and 295 deletions

View File

@ -57,25 +57,44 @@ See [doc/contributors/index.md](./doc/contributors/index.md) for more informatio
<br> <br>
## PR Standards
We expect the following from pull requests (it makes things easier):
- If you're closing an issue, please reference that issue in the PR description
- Avoid whitespace changes
- No regressions for "appspace" (Puter apps)
<br>
## Commit Messages ## Commit Messages
Use the imperative, as is the convention in the Linux kernel: **Note:** we will squash-merge some PRs so they follow . Large PRs should follow conventional commits also. The instructions below are outdated but suitable for most PRs.
- correct: `Improve performance of readdir` ### Conventional Commits
- incorrect: `Improved readdir` We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) with the following prefixes:
- incorrect: `Improving readdir` - `fix:` for bug fixes
- `dev:` instead of `refactor:`; covers more basis
- `tweak:` for small updates
- `sync:` when updating data from another source
- `feat:` for a commit that first introduces a new feature
Commit messages after the prefix should use the imperative (the same convention used in the repo for Linux, which Git was built for):
- correct: `dev: improve performance of readdir`
- incorrect: `dev: improved readdir`
- incorrect: `dev: improving readdir`
We have the following exceptions to this rule: We have the following exceptions to this rule:
- If the commit message is in _past tense_, it's a shorthand for the following: - If the commit message is in _past tense_, it's a shorthand for the following:
- `Apply changes that would be applied after one had <past tense message>` - `dev: apply changes that would be applied after one had <past tense message>`
- If the commit message is in _present tense_, it's shorthand for the following: - If the commit message is in _present tense_, it's shorthand for the following:
- `Apply changes that would be applied after <present-tense message>` - `dev: apply changes that would be applied after <present-tense message>`
For example, the following are correct: For example, the following are correct:
- `Improved readdir` - `dev: improved readdir`
- interpret this as: `Apply changes that would be applied after one had improved readdir` - interpret this as: `dev: apply changes that would be applied after one had improved readdir`
- `Improving readdir` - `dev: improving readdir`
- interpret this as: `Apply changes that would be applied after improving readdir` - interpret this as: `dev: apply changes that would be applied after improving readdir`
<br> <br>

View File

@ -132,18 +132,25 @@ This repository, including all its contents, sub-projects, modules, and componen
## Translations ## Translations
- [Arabic / العربية](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ar.md)
- [Bengali / বাংলা](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.bn.md) - [Bengali / বাংলা](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.bn.md)
- [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md) - [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md)
- [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md)
- [English](https://github.com/HeyPuter/puter/blob/main/README.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md)
- [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [Finnish / Suomi](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fi.md)
- [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fr.md)
- [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md)
- [Indonesian / Bahasa Indonesia](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.id.md) - [Indonesian / Bahasa Indonesia](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.id.md)
- [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) - [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md)
- [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md)
- [Korean / 한국어](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ko.md)
- [Polish / Polski](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pl.md)
- [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md)
- [Romanian / Română](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ro.md)
- [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md)
- [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md)
- [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) - [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md)
- [Thai / ไทย](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.th.md)
- [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md)
- [Urdu / اردو](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ur.md)
- [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) - [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md)

133
doc/i18n/README.ar.md Normal file
View File

@ -0,0 +1,133 @@
<h3 align="center"><img width="80" alt="Puter.com، الحاسوب السحابي الشخصي: جميع ملفاتك وتطبيقاتك وألعابك في مكان واحد يمكن الوصول إليه من أي مكان في أي وقت." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">نظام تشغيل الإنترنت! مجاني ومفتوح المصدر وقابل للاستضافة الذاتية.</h3>
<p align="center">
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="GitHub Release" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=latest%20version"> <img alt="GitHub License" src="https://img.shields.io/github/license/HeyPuter/puter">
</p>
<p align="center">
<a href="https://puter.com/"><strong>« عرض توضيحي مباشر »</strong></a>
<br />
<br />
<a href="https://puter.com">Puter.com</a>
·
<a href="https://docs.puter.com" target="_blank">مجموعة أدوات التطوير</a>
·
<a href="https://discord.com/invite/PQcx7Teh8u">ديسكورد</a>
·
<a href="https://www.youtube.com/@EricsPuterVideos">يوتيوب</a>
·
<a href="https://reddit.com/r/puter">ريديت</a>
·
<a href="https://twitter.com/HeyPuter">إكس (تويتر)</a>
·
<a href="https://hackerone.com/puter_h1b">مكافأة اكتشاف الثغرات</a>
</p>
<h3 align="center"><img width="800" style="border-radius:5px;" alt="لقطة شاشة" src="https://assets.puter.site/puter.com-screenshot-3.webp"></h3>
<br/>
## بيوتر
<div dir="rtl">
<p>بيوتر هو نظام تشغيل إنترنت متقدم ومفتوح المصدر، مصمم ليكون غنيًا بالميزات وسريعًا بشكل استثنائي وقابلًا للتوسع بدرجة كبيرة. يمكن استخدام بيوتر كـ:</p>
<ul>
<li>سحابة شخصية تعطي الأولوية للخصوصية لحفظ جميع ملفاتك وتطبيقاتك وألعابك في مكان آمن واحد، يمكن الوصول إليه من أي مكان وفي أي وقت.</li>
<li>منصة لبناء ونشر المواقع الإلكترونية وتطبيقات الويب والألعاب</li>
<li>بديل لـ Dropbox وGoogle Drive وOneDrive وغيرها، مع واجهة جديدة وميزات قوية.</li>
<li>بيئة سطح مكتب عن بُعد للخوادم ومحطات العمل.</li>
<li>مشروع ومجتمع ودود ومفتوح المصدر للتعلم عن تطوير الويب والحوسبة السحابية والأنظمة الموزعة والكثير غير ذلك!</li>
</ul>
</div>
<br/>
## البدء
### 💻 التطوير المحلي
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
سيؤدي هذا إلى تشغيل Puter على http://puter.localhost:4100 (أو المنفذ التالي المتاح).
<br/>
### 🐳 دوكر
```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
```
<br/>
### 🐙 دوكر كومبوز
#### لينكس/ماك
```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
```
<br/>
#### ويندوز
```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
```
<br/>
### ☁️ موقع Puter.com
متاح Puter كخدمة مستضافة على[**puter.com**](https://puter.com)الموقع
<br/>
## متطلبات النظام
- **Operating Systems:** لينكس، ماك، ويندوز
- **RAM** ٢ جيجابايت كحد أدنى (يوصى بـ ٤ جيجابايت)
- **Disk Space:** ١ جيجابايت مساحة حرة
- **Node.js:** الإصدار ١٦+ (يوصى بالإصدار ٢٢+)
- **npm:** أحدث إصدار مستقر
<br/>
## الدعم
تواصل مع المشرفين والمجتمع من خلال هذه القنوات:
- تقرير عن خطأ أو طلب ميزة؟ الرجاء [فتح مشكلة](https://github.com/HeyPuter/puter/issues/new/choose)
- دسكورد: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u)
- إكس (تويتر): [x.com/HeyPuter](https://x.com/HeyPuter)
- ريديت: [/reddit.com/r/puter](https://www.reddit.com/r/puter/)
- ماستودون: [mastodon.social/@puter](https://mastodon.social/@puter)
- مشاكل أمنية؟ [security@puter.com](mailto:security@puter.com)
- البريد الإلكتروني للمشرفين [hi@puter.com](mailto:hi@puter.com)
نحن دائمًا سعداء لمساعدتك في أي أسئلة قد تكون لديك. لا تتردد في السؤال!
<br/>
## الترخيص
هذا المستودع، بما في ذلك جميع محتوياته ومشاريعه الفرعية ووحداته ومكوناته، مرخص تحت [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) ما لم ينص على خلاف ذلك صراحةً. قد تخضع المكتبات الخارجية المدرجة في هذا المستودع لتراخيصها الخاصة.
<br/>

130
doc/i18n/README.fi.md Normal file
View File

@ -0,0 +1,130 @@
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Internetin käyttöjärjestelmä! Ilmainen, avoimen lähdekoodin ja itse isännöitävä.</h3>
<p align="center">
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="GitHub Release" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=viimeisin%20versio"> <img alt="GitHub License" src="https://img.shields.io/github/license/HeyPuter/puter">
</p>
<p align="center">
<a href="https://puter.com/"><strong>« LIVE DEMO »</strong></a>
<br />
<br />
<a href="https://puter.com">Puter.com</a>
·
<a href="https://docs.puter.com" target="_blank">SDK</a>
·
<a href="https://discord.com/invite/PQcx7Teh8u">Discord</a>
·
<a href="https://www.youtube.com/@EricsPuterVideos">YouTube</a>
·
<a href="https://reddit.com/r/puter">Reddit</a>
·
<a href="https://twitter.com/HeyPuter">X (Twitter)</a>
·
<a href="https://hackerone.com/puter_h1b">Bug Bounty</a>
</p>
<h3 align="center"><img width="800" style="border-radius:5px;" alt="näyttökuva" src="https://assets.puter.site/puter.com-screenshot-3.webp"></h3>
<br/>
## Puter
Puter on kehittynyt, avoimen lähdekoodin internetin käyttöjärjestelmä, joka on suunniteltu olemaan ominaisuuksiltaan rikas, poikkeuksellisen nopea ja erittäin laajennettava. Puteria voidaan käyttää:
- Yksityisyyttä kunnioittavana henkilökohtaisena pilvenä, johon voit tallentaa kaikki tiedostosi, sovelluksesi ja pelisi turvallisesti yhdessä paikassa, josta ne ovat saatavilla missä tahansa ja milloin tahansa.
- Alustana verkkosivustojen, web-sovellusten ja pelien rakentamiseen ja julkaisemiseen.
- Vaihtoehtona Dropboxille, Google Drivelle, OneDrivelle jne. tuoreella käyttöliittymällä ja tehokkailla ominaisuuksilla.
- Etätyöpöytäympäristönä palvelimille ja työasemille.
- Ystävällisenä, avoimen lähdekoodin projektina ja yhteisönä, jossa voit oppia verkkokehityksestä, pilvipalveluista, hajautetuista järjestelmistä ja paljon muusta!
<br/>
## Aloittaminen
### 💻 Paikallinen kehitys
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Tämä käynnistää Puterin osoitteessa http://puter.localhost:4100 (tai seuraavassa vapaassa portissa).
<br/>
### 🐳 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
```
<br/>
### 🐙 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
```
<br/>
#### 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
```
<br/>
### ☁️ Puter.com
Puter on saatavilla isännöitynä palveluna osoitteessa [**puter.com**](https://puter.com).
<br/>
## Järjestelmävaatimukset
- **Käyttöjärjestelmät:** Linux, macOS, Windows
- **RAM:** Vähintään 2GB (Suositeltu 4GB)
- **Levytila:** 1GB vapaata tilaa
- **Node.js:** Versio 16+ (Suositeltu versio 22+)
- **npm:** Uusin vakaa versio
<br/>
## Tuki
Ota yhteyttä ylläpitäjiin ja yhteisöön näiden kanavien kautta:
- Onko sinulla virheraportti tai ominaisuuspyyntö? Ole hyvä ja [avaa uusi issue](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)
- Turvallisuusongelmat? [security@puter.com](mailto:security@puter.com)
- Ota yhteyttä ylläpitäjiin sähköpostitse osoitteessa [hi@puter.com](mailto:hi@puter.com)
Olemme aina valmiita auttamaan sinua kaikissa kysymyksissäsi. Älä epäröi kysyä!
<br/>
## Lisenssi
Tämä repository, mukaan lukien kaikki sen sisältö, aliprojektit, moduulit ja komponentit, on lisensoitu [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt)-lisenssillä, ellei toisin mainita. Tämän repositoryn mukana tulevat kolmannen osapuolen kirjastot voivat olla omien lisenssiensä alaisia.
<br/>

123
doc/i18n/README.pl.md Normal file
View File

@ -0,0 +1,123 @@
<h3 align="center"><img width="80" alt="Puter.com, Osobisty Komputer Chmurowy: Wszystkie twoje pliki, aplikacje i gry w jednym miejscu, dostępne z dowolnego miejsca o dowolnej porze." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">System Operacyjny Internetu! Darmowy, Open-Source i Możliwy do Samodzielnego Hostowania.</h3>
<p align="center">
<img alt="Rozmiar repozytorium GitHub" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="Wydanie GitHub" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=latest%20version"> <img alt="Licencja GitHub" src="https://img.shields.io/github/license/HeyPuter/puter">
</p>
<p align="center">
<a href="https://puter.com/"><strong>« DEMO NA ŻYWO »</strong></a>
<br />
<br />
<a href="https://puter.com">Puter.com</a>
·
<a href="https://docs.puter.com" target="_blank">SDK</a>
·
<a href="https://discord.com/invite/PQcx7Teh8u">Discord</a>
·
<a href="https://www.youtube.com/@EricsPuterVideos">YouTube</a>
·
<a href="https://reddit.com/r/puter">Reddit</a>
·
<a href="https://twitter.com/HeyPuter">X (Twitter)</a>
·
<a href="https://hackerone.com/puter_h1b">Bug Bounty</a>
</p>
<h3 align="center"><img width="800" style="border-radius:5px;" alt="zrzut ekranu" src="https://assets.puter.site/puter.com-screenshot-3.webp"></h3>
<br/>
## Puter
Puter to zaawansowany, open-source'owy system operacyjny internetowy, zaprojektowany tak, aby był bogaty w funkcje, wyjątkowo szybki i wysoce rozszerzalny. Puter może być używany jako:
- Prywatna chmura osobista do przechowywania wszystkich plików, aplikacji i gier w jednym bezpiecznym miejscu, dostępnym z dowolnego miejsca o dowolnej porze.
- Platforma do budowania i publikowania stron internetowych, aplikacji webowych i gier.
- Alternatywa dla Dropbox, Google Drive, OneDrive itp. ze świeżym interfejsem i potężnymi funkcjami.
- Zdalne środowisko pulpitu dla serwerów i stacji roboczych.
- Przyjazny, open-source'owy projekt i społeczność do nauki o tworzeniu stron internetowych, chmurze obliczeniowej, systemach rozproszonych i wielu innych!
<br/>
## Rozpoczęcie pracy
## 💻 Rozwój lokalny
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
To uruchomi Puter na http://puter.localhost:4100 (lub na następnym dostępnym porcie).
<br/>
## 🐳 Docker
```bash
Copy code
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
```
<br/>
## 🐙 Docker Compose
## Linux/macOS
```bash
Copy code
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
```
<br/>
## 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
```
<br/>
## ☁️ Puter.com
Puter jest dostępny jako usługa hostowana na [**puter.com**](https://puter.com).
<br/>
## Wymagania systemowe
- **Systemy operacyjne:** Linux, macOS, Windows
- **RAM:** Minimum 2GB (zalecane 4GB)
- **Przestrzeń dyskowa:** 1GB wolnego miejsca
- **Node.js:** Wersja 16+ (zalecana wersja 22+)
- **npm:** Najnowsza stabilna wersja
<br/>
## Wsparcie
Połącz się z opiekunami i społecznością przez te kanały:
- Raport o błędzie lub prośba o funkcję? Proszę otworzyć zgłoszenie.
- Discord: discord.com/invite/PQcx7Teh8u
- X (Twitter): x.com/HeyPuter
- Reddit: reddit.com/r/puter/
- Mastodon: mastodon.social/@puter
- Problemy z bezpieczeństwem? security@puter.com
- Email do opiekunów: hi@puter.com
Zawsze chętnie pomożemy Ci z wszelkimi pytaniami, jakie możesz mieć. Nie wahaj się pytać!
<br/>
## Licencja
To repozytorium, w tym cała jego zawartość, podprojekty, moduły i komponenty, jest licencjonowane na podstawie [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), chyba że wyraźnie zaznaczono inaczej. Biblioteki stron trzecich zawarte w tym repozytorium mogą podlegać własnym licencjom.
<br/>

129
doc/i18n/README.ro.md Normal file
View File

@ -0,0 +1,129 @@
<h3 align="center"><img width="80" alt="Puter.com, Calculatorul Personal Cloud: Toate fișierele, aplicațiile și jocurile dumneavoastră într-un singur loc, accesibile de oriunde și oricând." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Sistemul de Operare Internet! Gratuit, Open-Source și Găzduibil Autonom.</h3>
<p align="center">
<img alt="Mărime GitHub repository" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="Versiune GitHub" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=ultima%20versiune"> <img alt="Licență GitHub" src="https://img.shields.io/github/license/HeyPuter/puter">
</p>
<p align="center">
<a href="https://puter.com/"><strong>« DEMO LIVE »</strong></a>
<br />
<br />
<a href="https://puter.com">Puter.com</a>
·
<a href="https://docs.puter.com" target="_blank">SDK</a>
·
<a href="https://discord.com/invite/PQcx7Teh8u">Discord</a>
·
<a href="https://www.youtube.com/@EricsPuterVideos">YouTube</a>
·
<a href="https://reddit.com/r/puter">Reddit</a>
·
<a href="https://twitter.com/HeyPuter">X (Twitter)</a>
·
<a href="https://hackerone.com/puter_h1b">Bug Bounty</a>
</p>
<h3 align="center"><img width="800" style="border-radius:5px;" alt="screenshot" src="https://assets.puter.site/puter.com-screenshot-3.webp"></h3>
<br/>
## Puter
Puter este un sistem de operare pe internet avansat, open-source, proiectat să fie bogat în funcții, extrem de rapid și foarte extensibil. Puter poate fi folosit ca:
- Un cloud personal care pune pe primul loc confidențialitatea pentru a păstra toate fișierele, aplicațiile și jocurile tale într-un loc sigur, accesibil de oriunde și oricând.
- O platforma pentru a construi și publica site-uri web, aplicații web și jocuri.
- O alternativă la Dropbox, Google Drive, OneDrive, etc. cu o interfață nouă și funcționalități puternice.
- Un mediu desktop la distanță pentru servere si stații de lucru.
- Un proiect prietenos, open-source și o comunitate pentru a învăța despre dezvoltarea web, cloud computing, sisteme distribuite și multe altele!
<br/>
## Începeți
### 💻 Dezvoltare Locală
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Aceasta va lansa Puter la adresa http://puter.localhost:4100 (sau la următorul port disponibil).
<br/>
### 🐳 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
```
<br/>
### 🐙 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
```
<br/>
#### 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
```
<br/>
### ☁️ Puter.com
Puter este disponibil ca serviciu găzduit la [**puter.com**](https://puter.com).
<br/>
## Cerințe de Sistem
- **Sisteme de Operare:** Linux, macOS, Windows
- **RAM:** 2GB minim (4GB recomandat)
- **Spațiu pe Disk:** 1GB spațiu liber
- **Node.js:** Versiunea 16+ (Versiunea 22+ recomandată)
- **npm:** Ultima versiune stabilă
<br/>
## Suport
Conectați-vă cu cei care asigură mentenanța proiectului și comunitatea prin intermediul acestor canale:
- Aveți o problemă sau doriți o funcționalitate nouă? Vă rugăm [să deschideți o problemă](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)
- Probleme de securitate? [security@puter.com](mailto:security@puter.com)
- Trimiteți un email celor care asigură mentenanța proiectul la [hi@puter.com](mailto:hi@puter.com)
Suntem întotdeauna bucuroși să vă ajutăm cu orice întrebări aveți. Nu ezitați să ne întrebați!
<br/>
## Licență
Acest depozit, inclusiv toate conținuturile sale, sub-proiectele, modulele și componentele, sunt licențiate sub [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), cu excepția cazului în care se menționează altfel în mod explicit. Bibliotecile terțe incluse în acest depozit pot fi supuse propriilor licențe.
<br/>

131
doc/i18n/README.th.md Normal file
View File

@ -0,0 +1,131 @@
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">ระบบปฏิบัติการอินเทอร์เน็ต ฟรี, โอเพ่นซอร์ส, และสามารถโฮสต์ได้ด้วยตนเอง</h3>
<p align="center">
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="GitHub Release" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=latest%20version"> <img alt="GitHub License" src="https://img.shields.io/github/license/HeyPuter/puter">
</p>
<p align="center">
<a href="https://puter.com/"><strong>« การสาธิตสด »</strong></a>
<br />
<br />
<a href="https://puter.com">Puter.com</a>
·
<a href="https://docs.puter.com" target="_blank">ชุดพัฒนาโปรแกรม</a>
·
<a href="https://discord.com/invite/PQcx7Teh8u">ดิสคอร์ด</a>
·
<a href="https://www.youtube.com/@EricsPuterVideos">ยูทูบ</a>
·
<a href="https://reddit.com/r/puter">เรดดิท</a>
·
<a href="https://twitter.com/HeyPuter">X (ทวิตเตอร์)</a>
·
<a href="https://hackerone.com/puter_h1b">นักล่าบั๊ก</a>
</p>
<h3 align="center"><img width="800" style="border-radius:5px;" alt="screenshot" src="https://assets.puter.site/puter.com-screenshot-3.webp"></h3>
<br/>
## พิวเตอร์
พิวเตอร์ เป็นระบบปฏิบัติการอินเทอร์เน็ตขั้นสูงแบบโอเพ่นซอร์สที่ออกแบบมาให้มีฟีเจอร์ครบถ้วน ความเร็วสูง และมีความสามารถที่จะขยายได้สูง. พิวเตอร์ สามารถใช้ได้เป็น:
- คลาวด์ส่วนตัว เพื่อเก็บไฟล์, แอพพลิเคชัน, และเกมทั้งหมดของคุณในที่เดียวที่ปลอดภัยและสามารถเข้าถึงได้ทุกที่ทุกเวลา
- แพลตฟอร์มสำหรับการสร้างและเผยแพร่เว็บไซต์, เว็บแอปพลิเคชัน, และเกม
- ทางเลือกอีกหนึ่งทางที่สามารถใช้แทน Dropbox, Google Drive, OneDrive ฯลฯ โดยที่มีอินเทอร์เฟซใหม่และฟีเจอร์ที่ทรงพลัง
- สภาพแวดล้อมสำหรับเดสก์ท็อประยะไกลที่ใช้กับเซิร์ฟเวอร์และสถานีทำงาน
- โครงการโอเพ่นซอร์สและชุมชนที่เป็นมิตรที่คุณสามารถเรียนรู้เกี่ยวกับการพัฒนาเว็บ, คลาวด์คอมพิวติ้ง, ระบบกระจาย, และอีกมากมาย
<br/>
## การเริ่มต้นใช้งาน
### 💻 การพัฒนาภายในเครื่อง
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
พิวเตอร์ จะถูกเปิดใช้งานที่ http://puter.localhost:4100 (หรือพอร์ตถัดไปที่ว่าง).
<br/>
### 🐳 ด็อกเกอร์
```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
```
<br/>
### 🐙 ด็อกเกอร์ คอมโพส
#### ลินุกซ์/แมคโอเอส
```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
```
<br/>
#### วินโดวส์
```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
```
<br/>
### ☁️ Puter.com
สามารถใช้งาน พิวเตอร์ ได้ในรูปแบบบริการโฮสต์ที่ [**puter.com**](https://puter.com).
<br/>
## ข้อกำหนดของระบบ
- **ระบบปฏิบัติการ:** ลินุกซ์ แมคโอเอส วินโดวส์
- **แรม:** อย่างน้อย 2GB (แนะนำ 4GB)
- **พื้นที่เก็บข้อมูล:** พื้นที่ว่าง 1GB
- **Node.js:** เวอร์ชัน 16+ (แนะนำเวอร์ชัน 22+)
- **npm:** เวอร์ชันล่าสุดที่เสถียร
<br/>
## การช่วยเหลือ
ติดต่อกับผู้ดูแลระบบและชุมชนผ่านช่องทางเหล่านี้:
- พบข้อผิดพลาดหรือขอฟีเจอร์ใหม่? กรุณา [เปิดปัญหา](https://github.com/HeyPuter/puter/issues/new/choose).
- ดิสคอร์ด: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u)
- X (ทวิตเตอร์): [x.com/HeyPuter](https://x.com/HeyPuter)
- เรดดิท: [reddit.com/r/puter/](https://www.reddit.com/r/puter/)
- มาสตอดอน: [mastodon.social/@puter](https://mastodon.social/@puter)
- ปัญหาด้านความปลอดภัย [security@puter.com](mailto:security@puter.com)
- ส่งอีเมลถึงผู้ดูแลระบบได้ที่ [hi@puter.com](mailto:hi@puter.com)
เรายินดีเสมอที่จะช่วยเหลือคุณกับทุกทุกคำถามที่คุณมี อย่าลังเลที่จะถาม
<br/>
## ลิขสิทธิ์
ที่เก็บข้อมูลนี้ รวมถึงเนื้อหาทั้งหมด, โครงการย่อย, โมดูล, และส่วนประกอบต่างๆ ได้รับใบอนุญาตภายใต้ [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) เว้นแต่จะมีการระบุไว้เป็นอย่างอื่นอย่างชัดเจน ไลบรารีจากบุคคลที่สามที่รวมอยู่ในที่เก็บข้อมูลนี้อาจอยู่ภายใต้ใบอนุญาตของตนเอง
<br/>

125
doc/i18n/README.ur.md Normal file
View File

@ -0,0 +1,125 @@
<h3 align="center"><img width="80" alt="Puter.com, ذاتی کلاؤڈ کمپیوٹر: آپ کی تمام فائلیں، ایپس، اور کھیل ایک جگہ پر، کہیں سے بھی اور کسی بھی وقت قابل رسائی۔" src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">انٹرنیٹ OS! مفت، اوپن سورس، اور خود میزبان.</h3>
<p align="center">
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="GitHub Release" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=latest%20version"> <img alt="GitHub License" src="https://img.shields.io/github/license/HeyPuter/puter">
</p>
<p align="center">
<a href="https://puter.com/"><strong>« لائیو ڈیمو »</strong></a>
<br />
<br />
<a href="https://puter.com">Puter.com</a>
·
<a href="https://docs.puter.com" target="_blank">SDK</a>
·
<a href="https://discord.com/invite/PQcx7Teh8u">ڈسکورڈ</a>
·
<a href="https://www.youtube.com/@EricsPuterVideos">یوٹیوب</a>
·
<a href="https://reddit.com/r/puter">ریڈڈٹ</a>
·
<a href="https://twitter.com/HeyPuter">ایکس (ٹوئٹر)</a>
·
<a href="https://hackerone.com/puter_h1b">بگ باؤنٹی</a>
</p>
<h3 align="center"><img width="800" style="border-radius:5px;" alt="اسکرین شاٹ" src="https://assets.puter.site/puter.com-screenshot-3.webp"></h3>
<br/>
## Puter
ایک جدید، اوپن سورس انٹرنیٹ آپریٹنگ سسٹم ہے جو کہ خصوصیات سے بھرپور، بہت تیز، اور انتہائی توسیع پذیر ہے۔ Puter
: کو استعمال کیا جا سکتا ہے Puter
- ایک پرائیویسی فرسٹ ذاتی کلاؤڈ کے طور پر تاکہ آپ کی تمام فائلیں، ایپس، اور کھیل ایک محفوظ جگہ پر رکھی جا سکیں، کہیں سے بھی اور کسی بھی وقت قابل رسائی ہوں۔
- ویب سائٹس، ویب ایپس، اور کھیل بنانے اور شائع کرنے کے لئے ایک پلیٹ فارم کے طور پر۔
- وغیرہ کا متبادل، نئے انٹرفیس اور طاقتور خصوصیات کے ساتھ۔ Dropbox، Google Drive، OneDrive
- سرورز اور ورک اسٹیشنز کے لیے ایک ریموٹ ڈیسک ٹاپ ماحول کے طور پر۔
- ویب ڈویلپمنٹ، کلاؤڈ کمپیوٹنگ، تقسیم شدہ نظاموں، اور بہت کچھ سیکھنے کے لیے ایک دوستانہ، اوپن سورس پروجیکٹ اور کمیونٹی!
<br/>
## شروع کرنے کا طریقہ
### 💻 مقامی ترقی
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
یہ Puter کو http://puter.localhost:4100 (یا اگلے دستیاب پورٹ) پر لانچ کرے گا۔
<br/>
🐳 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
```
<br/>
🐙 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
```
<br/>
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
```
<br/>
### ☁️ Puter.com
Puter کو [**puter.com**](https://puter.com) پر میزبان سروس کے طور پر دستیاب ہے۔
<br/>
## نظام کی ضروریات
- **آپریٹنگ سسٹمز:** لینکس، macOS، ونڈوز
- **RAM:** کم از کم 2GB (4GB تجویز کردہ)
- **ڈسک کی جگہ:** 1GB خالی جگہ
- **Node.js:** ورژن 16+ (ورژن 22+ تجویز کردہ)
- **npm:** تازہ ترین مستحکم ورژن
<br/>
## سپورٹ
منتظمین اور کمیونٹی سے جڑنے کے لیے یہ چینلز استعمال کریں:
- بگ رپورٹ یا فیچر درخواست؟ براہ کرم [ایک مسئلہ کھولیں](https://github.com/HeyPuter/puter/issues/new/choose).
- ڈسکورڈ: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u)
- ایکس (ٹوئٹر): [x.com/HeyPuter](https://x.com/HeyPuter)
- ریڈڈٹ: [reddit.com/r/puter/](https://www.reddit.com/r/puter/)
- ماسٹڈون: [mastodon.social/@puter](https://mastodon.social/@puter)
- سیکیورٹی کے مسائل؟ [security@puter.com](mailto:security@puter.com)
- منتظمین کو ای میل کریں [hi@puter.com](mailto:hi@puter.com)
ہم ہمیشہ آپ کی مدد کے لیے خوش ہیں۔ سوالات پوچھنے میں ہچکچاہٹ نہ کریں
!
<br/>
## لائسنس
اس ریپوزٹری، بشمول اس کے تمام مواد، ذیلی پروجیکٹس، ماڈیولز، اور کمپوننٹس، کو [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) کے تحت لائسنس کیا گیا ہے جب تک کہ واضح طور پر کہیں اور نہ کہا گیا ہو۔ اس ریپوزٹری میں شامل تھرڈ پارٹی لائبریریاں اپنی لائسنس کے تابع ہو سکتی ہیں۔
<br/>

View File

@ -5,16 +5,12 @@
### Self-Hosting Differences ### Self-Hosting Differences
Currently, the self-hosted version of Puter is different in a few ways from [Puter.com](https://puter.com): Currently, the self-hosted version of Puter is different in a few ways from [Puter.com](https://puter.com):
- There is no built-in way to install or create other apps (see below) - There is no built-in way to access apps from puter.com (see below)
- Several "core" apps are missing, such as **Code** or **Draw**, because we can't include them in this repository - Several "core" apps are missing, such as **Code** or **Draw**
- Some icons are different - Some assets are different
Work is ongoing to improve the **App Center** and make it available on self-hosted. Work is ongoing to improve the **App Center** and make it available on self-hosted.
Until then, it's possible to add other apps by manually editing the database file. Until then, it is still possible to add apps using the **Dev Center** app.
This process is not recommended unless you know what you are doing.
The file will appear after you first launch Puter, and should be found in `puter/data/puter-database.sqlite` for Docker,
or `volatile/runtime/puter-database.sqlite` otherwise.
You will need a database tool that can understand SQLite databases.
<br/> <br/>
@ -55,4 +51,4 @@ A warning will persist in the dev console until this user's
password is changed. Please login to this user and change the password as password is changed. Please login to this user and change the password as
your first step. your first step.
<br/> <br/>

60
package-lock.json generated
View File

@ -43,7 +43,7 @@
"dependencies": { "dependencies": {
"@heyputer/kv.js": "^0.1.3", "@heyputer/kv.js": "^0.1.3",
"@heyputer/multest": "^0.0.2", "@heyputer/multest": "^0.0.2",
"@heyputer/puter-js-common": "^1.0.0", "@heyputer/putility": "^1.0.0",
"@opentelemetry/api": "^1.4.1", "@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/auto-instrumentations-node": "^0.43.0",
"@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0",
@ -195,7 +195,7 @@
"webpack-cli": "^5.1.4" "webpack-cli": "^5.1.4"
} }
}, },
"asdf/puter-js-common": { "asdf/putility": {
"version": "1.0.0", "version": "1.0.0",
"extraneous": true, "extraneous": true,
"license": "UNLICENSED" "license": "UNLICENSED"
@ -2545,6 +2545,10 @@
"resolved": "src/backend", "resolved": "src/backend",
"link": true "link": true
}, },
"node_modules/@heyputer/gui": {
"resolved": "src/gui",
"link": true
},
"node_modules/@heyputer/kv.js": { "node_modules/@heyputer/kv.js": {
"version": "0.1.6", "version": "0.1.6",
"resolved": "https://registry.npmjs.org/@heyputer/kv.js/-/kv.js-0.1.6.tgz", "resolved": "https://registry.npmjs.org/@heyputer/kv.js/-/kv.js-0.1.6.tgz",
@ -2597,14 +2601,18 @@
"resolved": "src/phoenix", "resolved": "src/phoenix",
"link": true "link": true
}, },
"node_modules/@heyputer/puter-js-common": { "node_modules/@heyputer/puter-wisp": {
"resolved": "src/puter-js-common", "resolved": "src/puter-wisp",
"link": true "link": true
}, },
"node_modules/@heyputer/puterjs": { "node_modules/@heyputer/puterjs": {
"resolved": "src/puter-js", "resolved": "src/puter-js",
"link": true "link": true
}, },
"node_modules/@heyputer/putility": {
"resolved": "src/putility",
"link": true
},
"node_modules/@heyputer/terminal": { "node_modules/@heyputer/terminal": {
"resolved": "src/terminal", "resolved": "src/terminal",
"link": true "link": true
@ -12515,9 +12523,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/mocha": { "node_modules/mocha": {
"version": "10.6.0", "version": "10.7.3",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz",
"integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -15371,9 +15379,10 @@
"dev": true "dev": true
}, },
"node_modules/tiktoken": { "node_modules/tiktoken": {
"version": "1.0.15", "version": "1.0.16",
"resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.15.tgz", "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.16.tgz",
"integrity": "sha512-sCsrq/vMWUSEW29CJLNmPvWxlVp7yh2tlkAjpJltIKqp5CKf98ZNpdeHRmAlPVFlGEbswDc6SmI8vz64W/qErw==" "integrity": "sha512-hRcORIGF2YlAgWx3nzrGJOrKSJwLoc81HpXmMQk89632XAgURc7IeV2FgQ2iXo9z/J96fCvpsHg2kWoHcbj9fg==",
"license": "MIT"
}, },
"node_modules/tildify": { "node_modules/tildify": {
"version": "2.0.0", "version": "2.0.0",
@ -16441,7 +16450,7 @@
"dependencies": { "dependencies": {
"@heyputer/kv.js": "^0.1.3", "@heyputer/kv.js": "^0.1.3",
"@heyputer/multest": "^0.0.2", "@heyputer/multest": "^0.0.2",
"@heyputer/puter-js-common": "^1.0.0", "@heyputer/putility": "^1.0.0",
"@opentelemetry/api": "^1.4.1", "@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/auto-instrumentations-node": "^0.43.0",
"@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0",
@ -16616,8 +16625,8 @@
"webpack-cli": "^5.1.4" "webpack-cli": "^5.1.4"
} }
}, },
"packages/puter-js-common": { "packages/putility": {
"name": "@heyputer/puter-js-common", "name": "@heyputer/putility",
"version": "1.0.0", "version": "1.0.0",
"extraneous": true, "extraneous": true,
"license": "UNLICENSED" "license": "UNLICENSED"
@ -16661,7 +16670,7 @@
"@aws-sdk/client-textract": "^3.621.0", "@aws-sdk/client-textract": "^3.621.0",
"@heyputer/kv.js": "^0.1.3", "@heyputer/kv.js": "^0.1.3",
"@heyputer/multest": "^0.0.2", "@heyputer/multest": "^0.0.2",
"@heyputer/puter-js-common": "^1.0.0", "@heyputer/putility": "^1.0.0",
"@mistralai/mistralai": "^1.0.3", "@mistralai/mistralai": "^1.0.3",
"@opentelemetry/api": "^1.4.1", "@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/auto-instrumentations-node": "^0.43.0",
@ -16719,7 +16728,7 @@
"string-hash": "^1.1.3", "string-hash": "^1.1.3",
"string-length": "^6.0.0", "string-length": "^6.0.0",
"svgo": "^3.0.2", "svgo": "^3.0.2",
"tiktoken": "^1.0.15", "tiktoken": "^1.0.16",
"together-ai": "^0.6.0-alpha.4", "together-ai": "^0.6.0-alpha.4",
"tweetnacl": "^1.0.3", "tweetnacl": "^1.0.3",
"ua-parser-js": "^1.0.38", "ua-parser-js": "^1.0.38",
@ -16785,8 +16794,8 @@
} }
}, },
"src/gui": { "src/gui": {
"version": "2.3.0", "name": "@heyputer/gui",
"extraneous": true, "version": "2.4.0",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"workspaces": [ "workspaces": [
"src/*" "src/*"
@ -16901,10 +16910,21 @@
"webpack-cli": "^5.1.4" "webpack-cli": "^5.1.4"
} }
}, },
"src/puter-js-common": { "src/puter-wisp": {
"name": "@heyputer/puter-js-common", "name": "@heyputer/puter-wisp",
"version": "1.0.0", "version": "1.0.0",
"license": "UNLICENSED" "license": "AGPL-3.0-only"
},
"src/putil": {
"name": "@heyputer/putility",
"version": "1.0.0",
"extraneous": true,
"license": "AGPL-3.0-only"
},
"src/putility": {
"name": "@heyputer/putility",
"version": "1.0.0",
"license": "AGPL-3.0-only"
}, },
"src/strataparse": { "src/strataparse": {
"version": "0.0.0", "version": "0.0.0",

View File

@ -71,7 +71,7 @@ doing the useless work that reveals what the useful work is.
## Underlying Constructs ## Underlying Constructs
- [puter-js-common's README.md](../../packages/puter-js-common/README.md) - [putility's README.md](../../packages/putility/README.md)
- Whenever you see `AdvancedBase`, that's from here - Whenever you see `AdvancedBase`, that's from here
- Many things in backend extend this. Anything that doesn't only doesn't - Many things in backend extend this. Anything that doesn't only doesn't
because it was written before `AdvancedBase` existed. because it was written before `AdvancedBase` existed.

View File

@ -35,7 +35,7 @@ To function properly, Puter needs **CoreModule**, a database module,
and a storage module. and a storage module.
A module extends A module extends
[AdvancedBase](../../../puter-js-common/README.md) [AdvancedBase](../../../putility/README.md)
and implements and implements
an `install` method. The install method has one parameter, a an `install` method. The install method has one parameter, a
[Context](../../src/util/context.js) [Context](../../src/util/context.js)

View File

@ -12,7 +12,7 @@
"@aws-sdk/client-textract": "^3.621.0", "@aws-sdk/client-textract": "^3.621.0",
"@heyputer/kv.js": "^0.1.3", "@heyputer/kv.js": "^0.1.3",
"@heyputer/multest": "^0.0.2", "@heyputer/multest": "^0.0.2",
"@heyputer/puter-js-common": "^1.0.0", "@heyputer/putility": "^1.0.0",
"@mistralai/mistralai": "^1.0.3", "@mistralai/mistralai": "^1.0.3",
"@opentelemetry/api": "^1.4.1", "@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/auto-instrumentations-node": "^0.43.0",
@ -70,7 +70,7 @@
"string-hash": "^1.1.3", "string-hash": "^1.1.3",
"string-length": "^6.0.0", "string-length": "^6.0.0",
"svgo": "^3.0.2", "svgo": "^3.0.2",
"tiktoken": "^1.0.15", "tiktoken": "^1.0.16",
"together-ai": "^0.6.0-alpha.4", "together-ai": "^0.6.0-alpha.4",
"tweetnacl": "^1.0.3", "tweetnacl": "^1.0.3",
"ua-parser-js": "^1.0.38", "ua-parser-js": "^1.0.38",

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const Library = require("./definitions/Library"); const Library = require("./definitions/Library");
const { NotificationES } = require("./om/entitystorage/NotificationES"); const { NotificationES } = require("./om/entitystorage/NotificationES");
const { ProtectedAppES } = require("./om/entitystorage/ProtectedAppES"); const { ProtectedAppES } = require("./om/entitystorage/ProtectedAppES");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class DatabaseModule extends AdvancedBase { class DatabaseModule extends AdvancedBase {
async install (context) { async install (context) {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { Context } = require('./util/context'); const { Context } = require('./util/context');
const BaseService = require("./services/BaseService"); const BaseService = require("./services/BaseService");
const useapi = require('useapi'); const useapi = require('useapi');

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class LocalDiskStorageModule extends AdvancedBase { class LocalDiskStorageModule extends AdvancedBase {
async install (context) { async install (context) {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class PuterDriversModule extends AdvancedBase { class PuterDriversModule extends AdvancedBase {
async install () {} async install () {}

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class ThirdPartyDriversModule extends AdvancedBase { class ThirdPartyDriversModule extends AdvancedBase {
// constructor () { // constructor () {

View File

@ -482,6 +482,10 @@ module.exports = class APIError {
status: 422, status: 422,
message: 'This share can not be applied to this user.', message: 'This share can not be applied to this user.',
}, },
'no_origin_for_app': {
status: 400,
message: 'Puter apps must have a valid URL.'
},
// Chat // Chat
// TODO: specifying these errors here might be a violation // TODO: specifying these errors here might be a violation

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { quot } = require("../util/strutil"); const { quot } = require("../util/strutil");
const { TechnicalError } = require("../errors/TechnicalError"); const { TechnicalError } = require("../errors/TechnicalError");
const { print_error_help } = require("../errors/error_help_details"); const { print_error_help } = require("../errors/error_help_details");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { quot } = require("../util/strutil"); const { quot } = require("../util/strutil");
class ConfigLoader extends AdvancedBase { class ConfigLoader extends AdvancedBase {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { Context } = require('../util/context') const { Context } = require('../util/context')
const APIError = require("../api/APIError"); const APIError = require("../api/APIError");
const { AppUnderUserActorType, UserActorType } = require("../services/auth/Actor"); const { AppUnderUserActorType, UserActorType } = require("../services/auth/Actor");

View File

@ -27,7 +27,7 @@ const SystemFSEntryService = require('./storage/SystemFSEntryService.js');
const PerformanceMonitor = require('../monitor/PerformanceMonitor.js'); const PerformanceMonitor = require('../monitor/PerformanceMonitor.js');
const { NodePathSelector, NodeUIDSelector, NodeInternalIDSelector } = require('./node/selectors.js'); const { NodePathSelector, NodeUIDSelector, NodeInternalIDSelector } = require('./node/selectors.js');
const FSNodeContext = require('./FSNodeContext.js'); const FSNodeContext = require('./FSNodeContext.js');
const { AdvancedBase } = require('@heyputer/puter-js-common'); const { AdvancedBase } = require('@heyputer/putility');
const { Context } = require('../util/context.js'); const { Context } = require('../util/context.js');
const { simple_retry } = require('../util/retryutil.js'); const { simple_retry } = require('../util/retryutil.js');
const APIError = require('../api/APIError.js'); const APIError = require('../api/APIError.js');

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require('@heyputer/puter-js-common'); const { AdvancedBase } = require('@heyputer/putility');
const PathResolver = require('../../routers/filesystem_api/batch/PathResolver'); const PathResolver = require('../../routers/filesystem_api/batch/PathResolver');
const commands = require('./commands').commands; const commands = require('./commands').commands;
const { WorkUnit } = require('../../services/runtime-analysis/ExpectationService'); const { WorkUnit } = require('../../services/runtime-analysis/ExpectationService');

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { AsyncProviderFeature } = require("../../traits/AsyncProviderFeature"); const { AsyncProviderFeature } = require("../../traits/AsyncProviderFeature");
const { HLMkdir, QuickMkdir } = require("../hl_operations/hl_mkdir"); const { HLMkdir, QuickMkdir } = require("../hl_operations/hl_mkdir");
const { Context } = require("../../util/context"); const { Context } = require("../../util/context");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { id2path } = require("../../helpers"); const { id2path } = require("../../helpers");
const { PuterPath } = require("../lib/PuterPath"); const { PuterPath } = require("../lib/PuterPath");

View File

@ -1,4 +1,4 @@
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class BroadcastModule extends AdvancedBase { class BroadcastModule extends AdvancedBase {
async install (context) { async install (context) {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const BaseService = require("../../services/BaseService"); const BaseService = require("../../services/BaseService");
const { CLink } = require("./connection/CLink"); const { CLink } = require("./connection/CLink");
const { SLink } = require("./connection/SLink"); const { SLink } = require("./connection/SLink");

View File

@ -1,4 +1,4 @@
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { ChannelFeature } = require("../../../traits/ChannelFeature"); const { ChannelFeature } = require("../../../traits/ChannelFeature");
class BaseLink extends AdvancedBase { class BaseLink extends AdvancedBase {

View File

@ -1,4 +1,4 @@
const { AdvancedBase } = require('@heyputer/puter-js-common'); const { AdvancedBase } = require('@heyputer/putility');
class KeyPairHelper extends AdvancedBase { class KeyPairHelper extends AdvancedBase {
static MODULES = { static MODULES = {

View File

@ -90,6 +90,7 @@ class ClaudeService extends BaseService {
}); });
stream.write(str + '\n'); stream.write(str + '\n');
} }
stream.end();
})(); })();
return retval; return retval;

View File

@ -54,6 +54,7 @@ class GroqAIService extends BaseService {
}); });
stream.write(str + '\n'); stream.write(str + '\n');
} }
stream.end();
})(); })();
return retval; return retval;
} }

View File

@ -55,6 +55,7 @@ class MistralAIService extends BaseService {
}); });
stream.write(str + '\n'); stream.write(str + '\n');
} }
stream.end();
})(); })();
return retval; return retval;
} }

View File

@ -91,8 +91,7 @@ class OpenAICompletionService extends BaseService {
throw new Error('`messages` must be an array'); throw new Error('`messages` must be an array');
} }
model = model ?? 'gpt-3.5-turbo'; model = model ?? 'gpt-4o-mini';
// model = model ?? 'gpt-4o';
for ( let i = 0; i < messages.length; i++ ) { for ( let i = 0; i < messages.length; i++ ) {
let msg = messages[i]; let msg = messages[i];
@ -233,6 +232,7 @@ class OpenAICompletionService extends BaseService {
}); });
stream.write(str + '\n'); stream.write(str + '\n');
} }
stream.end();
})(); })();
return retval; return retval;
} }

View File

@ -1,4 +1,4 @@
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const config = require("../../config"); const config = require("../../config");
class PuterAIModule extends AdvancedBase { class PuterAIModule extends AdvancedBase {

View File

@ -59,6 +59,7 @@ class TogetherAIService extends BaseService {
}); });
stream.write(str + '\n'); stream.write(str + '\n');
} }
stream.end();
})(); })();
return retval; return retval;
} }

View File

@ -42,7 +42,7 @@ const DEFAULT_FILES = {
} }
}, },
"es": { "es": {
"date-limit": { "rate-limit": {
"max": 1000, "max": 1000,
"period": 30000 "period": 30000
} }
@ -90,7 +90,18 @@ class DefaultUserService extends BaseService {
if ( ! is_default_password ) return; if ( ! is_default_password ) return;
// show console widget // show console widget
this.default_user_widget = () => { this.default_user_widget = ({ is_docker }) => {
if ( is_docker ) {
// In Docker we keep the output as simple as possible because
// we're unable to determine the size of the terminal
return [
'Password for `admin`: ' + tmp_password,
// TODO: possible bug
// These blank lines are necessary for it to render and
// I'm not entirely sure why anymore.
'', '',
];
}
const lines = [ const lines = [
`Your admin user has been created!`, `Your admin user has been created!`,
`\x1B[31;1musername:\x1B[0m ${USERNAME}`, `\x1B[31;1musername:\x1B[0m ${USERNAME}`,
@ -100,6 +111,7 @@ class DefaultUserService extends BaseService {
surrounding_box('31;1', lines); surrounding_box('31;1', lines);
return lines; return lines;
}; };
this.default_user_widget.critical = true;
this.start_poll_({ tmp_password, user }); this.start_poll_({ tmp_password, user });
const svc_devConsole = this.services.get('dev-console'); const svc_devConsole = this.services.get('dev-console');
svc_devConsole.add_widget(this.default_user_widget); svc_devConsole.add_widget(this.default_user_widget);

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const config = require("../../config"); const config = require("../../config");
class SelfHostedModule extends AdvancedBase { class SelfHostedModule extends AdvancedBase {
@ -48,6 +48,12 @@ class SelfHostedModule extends AdvancedBase {
command: 'npm', command: 'npm',
args: ['run', 'start-webpack'], args: ['run', 'start-webpack'],
}, },
{
name: 'gui:webpack-watch',
directory: 'src/gui',
command: 'npm',
args: ['run', 'start-webpack'],
},
{ {
name: 'terminal:rollup-watch', name: 'terminal:rollup-watch',
directory: 'src/terminal', directory: 'src/terminal',
@ -111,6 +117,18 @@ class SelfHostedModule extends AdvancedBase {
'src/puter-js/dist/puter.dev.js'), 'src/puter-js/dist/puter.dev.js'),
route: '/puter.js/v2', route: '/puter.js/v2',
}); });
services.registerService('__serve-putilityjs-new', ServeSingleFileService, {
path: path_.resolve(__dirname,
RELATIVE_PATH,
'src/putility/dist/putility.dev.js'),
route: '/putility.js/v1',
});
services.registerService('__serve-gui-js', ServeSingleFileService, {
path: path_.resolve(__dirname,
RELATIVE_PATH,
'src/gui/dist/gui.dev.js'),
route: '/putility.js/v1',
});
} }
} }

View File

@ -1,4 +1,4 @@
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class TestDriversModule extends AdvancedBase { class TestDriversModule extends AdvancedBase {
async install (context) { async install (context) {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { WeakConstructorFeature } = require("../traits/WeakConstructorFeature"); const { WeakConstructorFeature } = require("../traits/WeakConstructorFeature");
const { Eq, And } = require("./query/query"); const { Eq, And } = require("./query/query");
const { Entity } = require("./entitystorage/Entity"); const { Entity } = require("./entitystorage/Entity");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { instance_ } = require("../../monitor/PerformanceMonitor"); const { instance_ } = require("../../monitor/PerformanceMonitor");
const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature");
const { Property } = require("./Property"); const { Property } = require("./Property");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature");
class PropType extends AdvancedBase { class PropType extends AdvancedBase {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature");
class Property extends AdvancedBase { class Property extends AdvancedBase {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature");
const { Context } = require("../../util/context"); const { Context } = require("../../util/context");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature");
class Entity extends AdvancedBase { class Entity extends AdvancedBase {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { BaseES } = require("./BaseES"); const { BaseES } = require("./BaseES");
const APIError = require("../../api/APIError"); const APIError = require("../../api/APIError");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { BaseES } = require("./BaseES"); const { BaseES } = require("./BaseES");
const APIError = require("../../api/APIError"); const APIError = require("../../api/APIError");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature");
class Predicate extends AdvancedBase { class Predicate extends AdvancedBase {

View File

@ -87,6 +87,13 @@ router.all('*', async function(req, res, next) {
} }
}); });
} }
if (path === '/putility/v1') {
return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'putility.js/v1.js'), function (err) {
if (err && err.statusCode) {
return res.status(err.statusCode).send('Error /putility.js')
}
});
}
} }
const db = Context.get('services').get('database').get(DB_READ, 'default'); const db = Context.get('services').get('database').get(DB_READ, 'default');

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const api_error_handler = require("../../api/api_error_handler"); const api_error_handler = require("../../api/api_error_handler");
const config = require("../../config"); const config = require("../../config");
const { get_user, get_app, id2path } = require("../../helpers"); const { get_user, get_app, id2path } = require("../../helpers");

View File

@ -117,7 +117,7 @@ module.exports = eggspress('/sign', {
if ( item.action === 'write' ) { if ( item.action === 'write' ) {
if ( ! await svc_acl.check(actor, node, 'write') ) { if ( ! await svc_acl.check(actor, node, 'write') ) {
throw await svc_acl.get_safe_acl_error(actor, node, 'write'); item.action = 'read';
} }
} }

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("../../../putility");
const NOOP = async () => {}; const NOOP = async () => {};

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const config = require("../config"); const config = require("../config");
const { Context } = require("../util/context"); const { Context } = require("../util/context");
const { CompositeError } = require("../util/errorutil"); const { CompositeError } = require("../util/errorutil");

View File

@ -20,11 +20,26 @@ const { consoleLogManager } = require('../util/consolelog');
const BaseService = require('./BaseService'); const BaseService = require('./BaseService');
class DevConsoleService extends BaseService { class DevConsoleService extends BaseService {
static MODULES = {
fs: require('fs'),
}
_construct () { _construct () {
this.static_lines = []; this.static_lines = [];
this.widgets = []; this.widgets = [];
this.identifiers = {}; this.identifiers = {};
this.has_updates = false; this.has_updates = false;
try {
const require = this.require;
const fs = require('fs');
this.is_docker = fs.existsSync('/.dockerenv');
} catch (e) {
// if this fails, we assume is_docker should
// be false.
this.log.error(e.message);
this.is_docker = false;
}
} }
turn_on_the_warning_lights () { turn_on_the_warning_lights () {
@ -60,7 +75,7 @@ class DevConsoleService extends BaseService {
let positions = []; let positions = [];
for ( const w of this.widgets ) { for ( const w of this.widgets ) {
let output; try { let output; try {
output = w(); output = w({ is_docker: this.is_docker });
} catch ( e ) { } catch ( e ) {
consoleLogManager.log_raw('error', e); consoleLogManager.log_raw('error', e);
to_remove.push(w); to_remove.push(w);
@ -78,6 +93,7 @@ class DevConsoleService extends BaseService {
for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) { for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) {
if ( size_ok() ) break; if ( size_ok() ) break;
const w = this.widgets[i]; const w = this.widgets[i];
if ( w.critical ) continue;
if ( ! w.unimportant ) continue; if ( ! w.unimportant ) continue;
n_hidden++; n_hidden++;
const [start, length] = positions[i]; const [start, length] = positions[i];
@ -89,8 +105,9 @@ class DevConsoleService extends BaseService {
} }
for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) { for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) {
if ( size_ok() ) break; if ( size_ok() ) break;
n_hidden++;
const w = this.widgets[i]; const w = this.widgets[i];
if ( w.critical ) continue;
n_hidden++;
const [start, length] = positions[i]; const [start, length] = positions[i];
this.static_lines.splice(start, length); this.static_lines.splice(start, length);
} }

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class EngPortalService extends AdvancedBase { class EngPortalService extends AdvancedBase {
static MODULES = { static MODULES = {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("../../../putility");
const { Context } = require("../util/context"); const { Context } = require("../util/context");
const { ContextAwareFeature } = require("../traits/ContextAwareFeature"); const { ContextAwareFeature } = require("../traits/ContextAwareFeature");
const { OtelFeature } = require("../traits/OtelFeature"); const { OtelFeature } = require("../traits/OtelFeature");

View File

@ -255,46 +255,9 @@ class PuterHomepageService extends BaseService {
? `<script>window.gui_env = 'prod';</script>` ? `<script>window.gui_env = 'prod';</script>`
: '' : ''
} }
${
((!bundled && manifest?.lib_paths)
? manifest.lib_paths.map(path => `<script type="text/javascript" src="${path}"></script>\n`)
: []).join('')
}
<script>
window.icons = {};
${(() => {
if ( !(!bundled && manifest) ) return '';
const html = [];
fs_.readdirSync(path_.join(gui_path, 'src/icons')).forEach(file => {
// skip dotfiles
if(file.startsWith('.'))
return;
// load image
let buff = new Buffer.from(fs_.readFileSync(path_.join(gui_path, 'src/icons') + '/' + file));
// convert to base64
let base64data = buff.toString('base64');
// add to `window.icons`
if(file.endsWith('.png'))
html.push(`window.icons['${file}'] = "data:image/png;base64,${base64data}";\n`);
else if(file.endsWith('.svg'))
html.push(`window.icons['${file}'] = "data:image/svg+xml;base64,${base64data}";\n`);
})
return html.join('');
})()}
</script>
${
((!bundled && manifest?.js_paths)
? manifest.js_paths.map(path => writeScriptTag(path))
: []).join('')
}
<!-- Load the GUI script --> <!-- Load the GUI script -->
<script ${ <script src="/dist/bundle.min.js"></script>
// !bundled ? ' type="module"' : ''
' type="module"'
} src="${(!bundled && manifest?.index) || '/dist/gui.js'}"></script>
<!-- Initialize GUI when document is loaded --> <!-- Initialize GUI when document is loaded -->
<script type="module"> <script type="module">
window.addEventListener('load', function() { window.addEventListener('load', function() {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const BaseService = require("./BaseService"); const BaseService = require("./BaseService");
class MapCollection extends AdvancedBase { class MapCollection extends AdvancedBase {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class ServicePatch extends AdvancedBase { class ServicePatch extends AdvancedBase {
patch ({ original_service }) { patch ({ original_service }) {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class StorageService extends AdvancedBase { class StorageService extends AdvancedBase {
constructor ({ services }) { constructor ({ services }) {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
class WSPushService extends AdvancedBase { class WSPushService extends AdvancedBase {
static MODULES = { static MODULES = {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const BaseService = require("../BaseService"); const BaseService = require("../BaseService");
const { Context } = require("../../util/context"); const { Context } = require("../../util/context");
const config = require("../../config"); const config = require("../../config");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("../../../../putility");
const { Context } = require("../../util/context"); const { Context } = require("../../util/context");
const { get_user, get_app } = require("../../helpers"); const { get_user, get_app } = require("../../helpers");
const config = require("../../config"); const config = require("../../config");

View File

@ -442,6 +442,9 @@ class AuthService extends BaseService {
async app_uid_from_origin (origin) { async app_uid_from_origin (origin) {
origin = this._origin_from_url(origin); origin = this._origin_from_url(origin);
if ( origin === null ) {
throw APIError.create('no_origin_for_app');
}
return await this._app_uid_from_origin(origin); return await this._app_uid_from_origin(origin);
} }

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("../../../../putility");
const BaseService = require("../BaseService"); const BaseService = require("../BaseService");
const { DB_WRITE, DB_READ } = require("./consts"); const { DB_WRITE, DB_READ } = require("./consts");

View File

@ -23,7 +23,7 @@ const { TypedValue } = require("./meta/Runtime");
const BaseService = require("../BaseService"); const BaseService = require("../BaseService");
const { Driver } = require("../../definitions/Driver"); const { Driver } = require("../../definitions/Driver");
const { PermissionUtil } = require("../auth/PermissionService"); const { PermissionUtil } = require("../auth/PermissionService");
const { Invoker } = require("@heyputer/puter-js-common/src/libs/invoker"); const { Invoker } = require("../../../../putility/src/libs/invoker");
const { get_user } = require("../../helpers"); const { get_user } = require("../../helpers");
/** /**

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("../../../../putility");
const { Context } = require("../../util/context"); const { Context } = require("../../util/context");
const { MultiValue } = require("../../util/multivalue"); const { MultiValue } = require("../../util/multivalue");
const { stream_to_buffer } = require("../../util/streamutil"); const { stream_to_buffer } = require("../../util/streamutil");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { BasicBase } = require("@heyputer/puter-js-common/src/bases/BasicBase"); const { BasicBase } = require("../../../../../putility/src/bases/BasicBase");
const types = require("../types"); const types = require("../types");
const { hash_serializable_object, stringify_serializable_object } = require("../../../util/datautil"); const { hash_serializable_object, stringify_serializable_object } = require("../../../util/datautil");

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { BasicBase } = require("@heyputer/puter-js-common/src/bases/BasicBase"); const { BasicBase } = require("../../../../../putility/src/bases/BasicBase");
const { TypeSpec } = require("./Construct"); const { TypeSpec } = require("./Construct");
class RuntimeEntity extends BasicBase { class RuntimeEntity extends BasicBase {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("../../../../putility");
const { is_valid_path } = require("../../filesystem/validation"); const { is_valid_path } = require("../../filesystem/validation");
const { is_valid_url, is_valid_uuid4 } = require("../../helpers"); const { is_valid_url, is_valid_uuid4 } = require("../../helpers");
const { FileFacade } = require("./FileFacade"); const { FileFacade } = require("./FileFacade");

View File

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const TeePromise = require("@heyputer/multest/src/util/TeePromise"); const TeePromise = require("@heyputer/multest/src/util/TeePromise");
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const { FileTracker } = require("./FileTracker"); const { FileTracker } = require("./FileTracker");
const { pausing_tee } = require("../../util/streamutil"); const { pausing_tee } = require("../../util/streamutil");

View File

@ -462,6 +462,11 @@ class LogService extends BaseService {
{ {
const fs = require('fs'); const fs = require('fs');
const path = '/var/puter/logs/heyputer'; const path = '/var/puter/logs/heyputer';
// Making this directory if it doesn't exist causes issues
// for users running with development instructions
if ( ! fs.existsSync('/var/puter') ) {
return;
}
try { try {
fs.mkdirSync(path, { recursive: true }); fs.mkdirSync(path, { recursive: true });
this.log_directory = path; this.log_directory = path;

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const APIError = require("../../api/APIError"); const APIError = require("../../api/APIError");
const { Context } = require("../../util/context"); const { Context } = require("../../util/context");
const BaseService = require("../BaseService"); const BaseService = require("../BaseService");

View File

@ -22,7 +22,7 @@
const axios = require('axios'); const axios = require('axios');
const { TeePromise } = require("../../util/promise"); const { TeePromise } = require("../../util/promise");
const { AdvancedBase } = require('@heyputer/puter-js-common'); const { AdvancedBase } = require('@heyputer/putility');
const FormData = require("form-data"); const FormData = require("form-data");
const { stream_to_the_void, buffer_to_stream } = require('../../util/streamutil'); const { stream_to_the_void, buffer_to_stream } = require('../../util/streamutil');
const BaseService = require('../BaseService'); const BaseService = require('../BaseService');

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("../../../putility");
/** /**
* MutliValue represents a subject with multiple values or a value with multiple * MutliValue represents a subject with multiple values or a value with multiple

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("../../../putility");
/** /**
* PathBuilder implements the builder pattern for building paths. * PathBuilder implements the builder pattern for building paths.

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const { AdvancedBase } = require("@heyputer/puter-js-common"); const { AdvancedBase } = require("@heyputer/putility");
const useapi = require("useapi"); const useapi = require("useapi");
const { BaseService } = require("../exports"); const { BaseService } = require("../exports");
const CoreModule = require("../src/CoreModule"); const CoreModule = require("../src/CoreModule");

View File

@ -264,6 +264,7 @@ section {
label, input[type="text"] { label, input[type="text"] {
display: block; display: block;
user-select: none;
} }
#delete-app { #delete-app {
@ -854,7 +855,11 @@ ol li:before {
float:right; margin-bottom: 10px; float:right; margin-bottom: 10px;
} }
.edit-app-navbar{ .edit-app-navbar{
overflow: hidden; margin-bottom: 60px; margin-top: 20px; overflow: hidden;
margin-bottom: 60px;
margin-top: 20px;
display: flex;
align-items: center;
} }
.app-title{ .app-title{
margin-top:0px; margin-top:0px;

View File

@ -245,7 +245,7 @@
<script src="./js/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" <script src="./js/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<script src="./js/jquery.dragster.js"></script> <script src="./js/jquery.dragster.js"></script>
<script src="/puter.js/v2"></script> <script src="https://js.puter.com/v2"></script>
<script src="./js/slugify.js"></script> <script src="./js/slugify.js"></script>
<script type="module" src="./js/html-entities.js"></script> <script type="module" src="./js/html-entities.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

View File

@ -440,7 +440,7 @@ function generate_edit_app_section(app) {
let h = ``; let h = ``;
h += ` h += `
<div class="edit-app-navbar"> <div class="edit-app-navbar">
<div style="float:left; min-width: 700px;"> <div style="flex-grow:1;">
<img class="app-icon" data-uid="${html_encode(app.uid)}" src="${html_encode(!app.icon ? './img/app.svg' : app.icon)}"> <img class="app-icon" data-uid="${html_encode(app.uid)}" src="${html_encode(!app.icon ? './img/app.svg' : app.icon)}">
<h3 class="app-title" data-uid="${html_encode(app.uid)}">${html_encode(app.title)}</h3> <h3 class="app-title" data-uid="${html_encode(app.uid)}">${html_encode(app.title)}</h3>
<div style="margin-top: 4px; margin-bottom: 4px;"> <div style="margin-top: 4px; margin-bottom: 4px;">
@ -475,6 +475,7 @@ function generate_edit_app_section(app) {
<div class="success" id="edit-app-success">App has been successfully updated.<span class="close-success-msg">&times;</span></div> <div class="success" id="edit-app-success">App has been successfully updated.<span class="close-success-msg">&times;</span></div>
<input type="hidden" id="edit-app-uid" value="${html_encode(app.uid)}"> <input type="hidden" id="edit-app-uid" value="${html_encode(app.uid)}">
<h3 style="border-bottom: 1px solid #EEE; margin-top: 40px;">Basic Info</h3>
<label for="edit-app-title">Title</label> <label for="edit-app-title">Title</label>
<input type="text" id="edit-app-title" placeholder="My Awesome App!" value="${html_encode(app.title)}"> <input type="text" id="edit-app-title" placeholder="My Awesome App!" value="${html_encode(app.title)}">
@ -487,45 +488,6 @@ function generate_edit_app_section(app) {
<label for="edit-app-app-id">App ID</label> <label for="edit-app-app-id">App ID</label>
<input type="text" style="width: 362px;" class="app-uid" value="${html_encode(app.uid)}" readonly> <input type="text" style="width: 362px;" class="app-uid" value="${html_encode(app.uid)}" readonly>
<div>
<input type="checkbox" id="edit-app-background" name="edit-app-background" value="true" style="margin-top:30px;" ${app.background ? 'checked' : ''}>
<label for="edit-app-background" style="display: inline;">Run as a background process.</label>
</div>
<div>
<input type="checkbox" id="edit-app-fullpage-on-landing" name="edit-app-fullpage-on-landing" value="true" style="margin-top:30px;" ${app.metadata?.fullpage_on_landing ? 'checked' : ''}>
<label for="edit-app-fullpage-on-landing" style="display: inline;">Load in full-page mode when a user lands directly on this app.</label>
</div>
<div>
<input type="checkbox" id="edit-app-maximize-on-start" name="edit-app-maximize-on-start" value="true" style="margin-top:30px;" ${maximize_on_start ? 'checked' : ''}>
<label for="edit-app-maximize-on-start" style="display: inline;">Maximize window on start</label>
</div>
<div>
<label for="edit-app-window-width">Window Width</label>
<input type="number" id="edit-app-window-width" placeholder="800" value="${html_encode(app.metadata?.window_size?.width ?? 800)}" style="width:200px;" ${maximize_on_start ? 'disabled' : ''}>
<label for="edit-app-window-height">Window Height</label>
<input type="number" id="edit-app-window-height" placeholder="600" value="${html_encode(app.metadata?.window_size?.height ?? 600)}" style="width:200px;" ${maximize_on_start ? 'disabled' : ''}>
</div>
<div style="margin-top:30px;">
<label for="edit-app-window-top">Window Top</label>
<input type="number" id="edit-app-window-top" placeholder="100" value="${app.metadata?.window_position?.top ? html_encode(app.metadata.window_position.top) : ''}" style="width:200px;" ${maximize_on_start ? 'disabled' : ''}>
<label for="edit-app-window-left">Window Left</label>
<input type="number" id="edit-app-window-left" placeholder="100" value="${app.metadata?.window_position?.left ? html_encode(app.metadata.window_position.left) : ''}" style="width:200px;" ${maximize_on_start ? 'disabled' : ''}>
</div>
<div style="margin-top:30px;">
<input type="checkbox" id="edit-app-window-resizable" name="edit-app-window-resizable" value="true" ${app.metadata?.window_resizable ? 'checked' : ''}>
<label for="edit-app-window-resizable" style="display: inline;">Window Resizable</label>
</div>
<div style="margin-top:30px;">
<input type="checkbox" id="edit-app-hide-titlebar" name="edit-app-hide-titlebar" value="true" ${app.metadata?.hide_titlebar ? 'checked' : ''}>
<label for="edit-app-hide-titlebar" style="display: inline;">Hide Titlebar</label>
</div>
<label for="edit-app-icon">Icon</label> <label for="edit-app-icon">Icon</label>
<div id="edit-app-icon" style="background-image:url(${!app.icon ? './img/app.svg' : html_encode(app.icon)});" ${app.icon ? 'data-url="' + html_encode(app.icon) + '"' : ''}> <div id="edit-app-icon" style="background-image:url(${!app.icon ? './img/app.svg' : html_encode(app.icon)});" ${app.icon ? 'data-url="' + html_encode(app.icon) + '"' : ''}>
<div id="change-app-icon">Change App Icon</div> <div id="change-app-icon">Change App Icon</div>
@ -539,6 +501,47 @@ function generate_edit_app_section(app) {
<p style="margin-top: 10px; font-size:13px;">A comma-separated list of file type specifiers. For example if you include <code>.txt</code>, your apps could be opened when a user clicks on a TXT file.</p> <p style="margin-top: 10px; font-size:13px;">A comma-separated list of file type specifiers. For example if you include <code>.txt</code>, your apps could be opened when a user clicks on a TXT file.</p>
<textarea id="edit-app-filetype-associations" placeholder=".txt, .jpg, application/json">${app.filetype_associations}</textarea> <textarea id="edit-app-filetype-associations" placeholder=".txt, .jpg, application/json">${app.filetype_associations}</textarea>
<h3 style="border-bottom: 1px solid #EEE; margin-top: 50px; margin-bottom: 0px;">Window Settings</h3>
<div>
<input type="checkbox" id="edit-app-background" name="edit-app-background" value="true" style="margin-top:30px;" ${app.background ? 'checked' : ''}>
<label for="edit-app-background" style="display: inline;">Run as a background process.</label>
</div>
<div>
<input type="checkbox" id="edit-app-fullpage-on-landing" name="edit-app-fullpage-on-landing" value="true" style="margin-top:30px;" ${app.metadata?.fullpage_on_landing ? 'checked' : ''} ${app.background ? 'disabled' : ''}>
<label for="edit-app-fullpage-on-landing" style="display: inline;">Load in full-page mode when a user lands directly on this app.</label>
</div>
<div>
<input type="checkbox" id="edit-app-maximize-on-start" name="edit-app-maximize-on-start" value="true" style="margin-top:30px;" ${maximize_on_start ? 'checked' : ''} ${app.background ? 'disabled' : ''}>
<label for="edit-app-maximize-on-start" style="display: inline;">Maximize window on start</label>
</div>
<div>
<label for="edit-app-window-width">Initial window width</label>
<input type="number" id="edit-app-window-width" placeholder="680" value="${html_encode(app.metadata?.window_size?.width ?? 680)}" style="width:200px;" ${maximize_on_start || app.background ? 'disabled' : ''}>
<label for="edit-app-window-height">Initial window height</label>
<input type="number" id="edit-app-window-height" placeholder="380" value="${html_encode(app.metadata?.window_size?.height ?? 380)}" style="width:200px;" ${maximize_on_start || app.background ? 'disabled' : ''}>
</div>
<div style="margin-top:30px;">
<label for="edit-app-window-top">Initial window top</label>
<input type="number" id="edit-app-window-top" placeholder="100" value="${app.metadata?.window_position?.top ? html_encode(app.metadata.window_position.top) : ''}" style="width:200px;" ${maximize_on_start || app.background ? 'disabled' : ''}>
<label for="edit-app-window-left">Initial window left</label>
<input type="number" id="edit-app-window-left" placeholder="100" value="${app.metadata?.window_position?.left ? html_encode(app.metadata.window_position.left) : ''}" style="width:200px;" ${maximize_on_start || app.background ? 'disabled' : ''}>
</div>
<div style="margin-top:30px;">
<input type="checkbox" id="edit-app-window-resizable" name="edit-app-window-resizable" value="true" ${app.metadata?.window_resizable ? 'checked' : ''} ${app.background ? 'disabled' : ''}>
<label for="edit-app-window-resizable" style="display: inline;">Resizable window</label>
</div>
<div style="margin-top:30px;">
<input type="checkbox" id="edit-app-hide-titlebar" name="edit-app-hide-titlebar" value="true" ${app.metadata?.hide_titlebar ? 'checked' : ''} ${app.background ? 'disabled' : ''}>
<label for="edit-app-hide-titlebar" style="display: inline;">Hide window titlebar</label>
</div>
<hr style="margin-top: 40px;">
<button type="button" class="edit-app-save-btn button button-primary">Save</button> <button type="button" class="edit-app-save-btn button button-primary">Save</button>
</form> </form>
</div> </div>
@ -1108,7 +1111,7 @@ $(document).on('click', '#edit-app-icon', async function (e) {
let mimeType = getMimeType(fileExtension); let mimeType = getMimeType(fileExtension);
// Replace MIME type in the data URL // Replace MIME type in the data URL
image = image.replace('data:application/octet-stream;base64', `data:image/${mimeType};base64`); image = image.replace('data:application/octet-stream;base64', `data:${mimeType};base64`);
$('#edit-app-icon').css('background-image', `url(${image})`); $('#edit-app-icon').css('background-image', `url(${image})`);
$('#edit-app-icon').attr('data-base64', image); $('#edit-app-icon').attr('data-base64', image);
@ -1315,11 +1318,31 @@ function sort_apps() {
let sorted_apps; let sorted_apps;
// sort // sort
if (sortDirection === 'asc') if (sortDirection === 'asc'){
sorted_apps = apps.sort((a, b) => a[sortBy] > b[sortBy] ? 1 : -1); sorted_apps = apps.sort((a, b) => {
else if(sortBy === 'name'){
sorted_apps = apps.sort((a, b) => a[sortBy] < b[sortBy] ? 1 : -1); return a[sortBy].localeCompare(b[sortBy]);
}else if(sortBy === 'created_at'){
return new Date(a[sortBy]) - new Date(b[sortBy]);
} else if(sortBy === 'user_count' || sortBy === 'open_count'){
return a.stats[sortBy] - b.stats[sortBy];
}else{
a[sortBy] > b[sortBy] ? 1 : -1
}
});
}else{
sorted_apps = apps.sort((a, b) => {
if(sortBy === 'name'){
return b[sortBy].localeCompare(a[sortBy]);
}else if(sortBy === 'created_at'){
return new Date(b[sortBy]) - new Date(a[sortBy]);
} else if(sortBy === 'user_count' || sortBy === 'open_count'){
return b.stats[sortBy] - a.stats[sortBy];
}else{
b[sortBy] > a[sortBy] ? 1 : -1
}
});
}
// refresh app list // refresh app list
$('.app-card').remove(); $('.app-card').remove();
sorted_apps.forEach(app => { sorted_apps.forEach(app => {
@ -2084,4 +2107,30 @@ $(document).on('change', '#edit-app-maximize-on-start', function (e) {
$('#edit-app-window-width, #edit-app-window-height').prop('disabled', false); $('#edit-app-window-width, #edit-app-window-height').prop('disabled', false);
$('#edit-app-window-top, #edit-app-window-left').prop('disabled', false); $('#edit-app-window-top, #edit-app-window-left').prop('disabled', false);
} }
}) })
$(document).on('change', '#edit-app-background', function (e) {
if($('#edit-app-background').is(":checked")){
disable_window_settings()
}else{
enable_window_settings()
}
})
function disable_window_settings(){
$('#edit-app-maximize-on-start').prop('disabled', true);
$('#edit-app-fullpage-on-landing').prop('disabled', true);
$('#edit-app-window-width, #edit-app-window-height').prop('disabled', true);
$('#edit-app-window-top, #edit-app-window-left').prop('disabled', true);
$('#edit-app-window-resizable').prop('disabled', true);
$('#edit-app-hide-titlebar').prop('disabled', true);
}
function enable_window_settings(){
$('#edit-app-maximize-on-start').prop('disabled', false);
$('#edit-app-fullpage-on-landing').prop('disabled', false);
$('#edit-app-window-width, #edit-app-window-height').prop('disabled', false);
$('#edit-app-window-top, #edit-app-window-left').prop('disabled', false);
$('#edit-app-window-resizable').prop('disabled', false);
$('#edit-app-hide-titlebar').prop('disabled', false);
}

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; import { PosixError } from '@heyputer/putility/src/PosixError.js';
import path_ from 'path-browserify'; import path_ from 'path-browserify';
let debug = false; let debug = false;

View File

@ -0,0 +1,81 @@
Multiple things attempted when trying to add icons to the bundle.
None of this worked - eventually just prepended text on emit instead.
```javascript
// compilation.hooks.processAssets.tap(
// {
// name: 'AddImportPlugin',
// stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
// },
// (assets) => {
// for (const assetName of Object.keys(assets)) {
// if (assetName.endsWith('.js')) {
// const source = assets[assetName].source();
// const newSource = `${icons}\n${source}`;
// compilation.updateAsset(assetName, new compiler.webpack.sources.RawSource(newSource));
// }
// }
// }
// );
// Inject into bundle
// console.log('adding this:' + icons);
// compilation.assets['icons-thing'] = {
// source: () => icons,
// size: () => icons.length,
// };
// compilation.addModule({
// identifier() {
// return 'icons-thing';
// },
// build() {
// this._source = {
// source() {
// return content;
// },
// size() {
// return content.length;
// }
// };
// }
// });
// Add the generated module to Webpack's internal modules
// compilation.hooks.optimizeModules.tap('IconsPlugin', (modules) => {
// const virtualModule = {
// identifier: () => 'icons.js',
// readableIdentifier: () => 'icons.js',
// build: () => {},
// source: () => icons,
// size: () => icons.length,
// chunks: [],
// assets: [],
// hash: () => 'icons',
// };
// modules.push(virtualModule);
// });
});
// this.hooks.entryOption.tap('IconsPlugin', (context, entry) => {
// entry.main.import.push('icons-thing');
// });
// this.hooks.make.tapAsync('InjectTextEntryPlugin', (compilation, callback) => {
// // Create a new asset (fake module) from the generated content
// const content = `console.log('${this.options.text}');`;
// callback();
// });
// this.hooks.entryOption.tap('IconsPlugin', (context, entry) => {
// });
// this.hooks.entryOption.tap('InjectTextEntryPlugin', (context, entry) => {
// // Add this as an additional entry point
// this.options.entry = {
// ...this.options.entry,
// 'generated-entry': '// FINDME\n'
// };
// });
```

View File

@ -28,7 +28,8 @@
"test": "mocha ./packages/phoenix/test ./packages/phoenix/packages/contextlink/test", "test": "mocha ./packages/phoenix/test ./packages/phoenix/packages/contextlink/test",
"start=gui": "nodemon --exec \"node dev-server.js\" ", "start=gui": "nodemon --exec \"node dev-server.js\" ",
"build": "node ./build.js", "build": "node ./build.js",
"check-translations": "node tools/check-translations.js" "check-translations": "node tools/check-translations.js",
"start-webpack": "webpack --watch --devtool source-map"
}, },
"workspaces": [ "workspaces": [
"src/*" "src/*"

View File

@ -10,7 +10,6 @@
"/lib/jquery-ui-1.13.2/jquery-ui.min.js", "/lib/jquery-ui-1.13.2/jquery-ui.min.js",
"/lib/lodash@4.17.21.min.js", "/lib/lodash@4.17.21.min.js",
"/lib/jquery.dragster.js", "/lib/jquery.dragster.js",
"/lib/jquery.menu-aim.js",
"/lib/html-entities.js", "/lib/html-entities.js",
"/lib/timeago.min.js", "/lib/timeago.min.js",
"/lib/iro.min.js", "/lib/iro.min.js",

View File

@ -29,9 +29,9 @@ import download from './helpers/download.js';
import path from "./lib/path.js"; import path from "./lib/path.js";
import UIContextMenu from './UI/UIContextMenu.js'; import UIContextMenu from './UI/UIContextMenu.js';
import update_mouse_position from './helpers/update_mouse_position.js'; import update_mouse_position from './helpers/update_mouse_position.js';
import launch_app from './helpers/launch_app.js';
import item_icon from './helpers/item_icon.js'; import item_icon from './helpers/item_icon.js';
window.ipc_handlers = {};
/** /**
* In Puter, apps are loaded in iframes and communicate with the graphical user interface (GUI), and each other, using the postMessage API. * In Puter, apps are loaded in iframes and communicate with the graphical user interface (GUI), and each other, using the postMessage API.
* The following sets up an Inter-Process Messaging System between apps and the GUI that enables communication * The following sets up an Inter-Process Messaging System between apps and the GUI that enables communication
@ -88,6 +88,24 @@ window.addEventListener('message', async (event) => {
const msg_id = event.data.uuid; const msg_id = event.data.uuid;
const app_name = $(target_iframe).attr('data-app'); const app_name = $(target_iframe).attr('data-app');
const app_uuid = $el_parent_window.attr('data-app_uuid'); const app_uuid = $el_parent_window.attr('data-app_uuid');
// New IPC handlers should be registered here.
// Do this by calling `register_ipc_handler` of IPCService.
if ( window.ipc_handlers.hasOwnProperty(event.data.msg) ) {
// The IPC context contains information about the call
const ipc_context = {
appInstanceId: event.data.appInstanceID,
};
// Registered IPC handlers are an object with a `handle()`
// method. We call it "spec" here, meaning specification.
const spec = window.ipc_handlers[event.data.msg];
await spec.handler(event.data, { msg_id, ipc_context });
// Early-return to avoid redundant invokation of any
// legacy IPC handler.
return;
}
// todo validate all event.data stuff coming from the client (e.g. event.data.message, .msg, ...) // todo validate all event.data stuff coming from the client (e.g. event.data.message, .msg, ...)
//------------------------------------------------- //-------------------------------------------------
@ -846,25 +864,6 @@ window.addEventListener('message', async (event) => {
window.watchItems[event.data.item_uid].push(event.data.appInstanceID); window.watchItems[event.data.item_uid].push(event.data.appInstanceID);
} }
//-------------------------------------------------------- //--------------------------------------------------------
// launchApp
//--------------------------------------------------------
else if(event.data.msg === 'launchApp'){
// TODO: Determine if the app is allowed to launch child apps? We may want to limit this to prevent abuse.
// remember app for launch callback later
const child_instance_id = window.uuidv4();
window.child_launch_callbacks[child_instance_id] = {
parent_instance_id: event.data.appInstanceID,
launch_msg_id: msg_id,
};
// launch child app
launch_app({
name: event.data.app_name ?? app_name,
args: event.data.args ?? {},
parent_instance_id: event.data.appInstanceID,
uuid: child_instance_id,
});
}
//--------------------------------------------------------
// readAppDataFile // readAppDataFile
//-------------------------------------------------------- //--------------------------------------------------------
else if(event.data.msg === 'readAppDataFile' && event.data.path !== undefined){ else if(event.data.msg === 'readAppDataFile' && event.data.path !== undefined){

View File

@ -986,7 +986,7 @@ async function UIDesktop(options){
// 'show desktop' // 'show desktop'
if(window.is_fullpage_mode){ if(window.is_fullpage_mode){
ht += `<a href="/" class="show-desktop-btn toolbar-btn antialiased" target="_blank" title="Show Desktop">Show Desktop <img src="${window.icons['launch-white.svg']}" style="width: 15px; height: 15px; margin-left: 5px;"></a>`; ht += `<a href="/" class="show-desktop-btn toolbar-btn antialiased" target="_blank" title="Show Desktop">Show Desktop <img src="${window.icons['launch-white.svg']}" style="width: 10px; height: 10px; margin-left: 5px;"></a>`;
} }
// refer // refer
@ -994,6 +994,9 @@ async function UIDesktop(options){
ht += `<div class="toolbar-btn refer-btn" title="Refer" style="background-image:url(${window.icons['gift.svg']});"></div>`; ht += `<div class="toolbar-btn refer-btn" title="Refer" style="background-image:url(${window.icons['gift.svg']});"></div>`;
} }
// github
ht += `<a href="https://github.com/HeyPuter/puter" target="_blank" class="toolbar-btn" title="GitHub" style="background-image:url(${window.icons['logo-github-white.svg']});"></a>`;
// do not show the fullscreen button on mobile devices since it's broken // do not show the fullscreen button on mobile devices since it's broken
if(!isMobile.phone){ if(!isMobile.phone){
// fullscreen button // fullscreen button
@ -1019,6 +1022,29 @@ async function UIDesktop(options){
// adjust window container to take into account the toolbar height // adjust window container to take into account the toolbar height
$('.window-container').css('top', window.toolbar_height); $('.window-container').css('top', window.toolbar_height);
//--------------------------------------------------------------------------------------
// Determine if an app was launched from URL
// i.e. https://puter.com/app/<app_name>
//--------------------------------------------------------------------------------------
if(window.url_paths[0]?.toLocaleLowerCase() === 'app' && window.url_paths[1]){
window.app_launched_from_url = window.url_paths[1];
// get app metadata
try{
window.app_launched_from_url = await puter.apps.get(window.url_paths[1])
window.is_fullpage_mode = window.app_launched_from_url.metadata?.fullpage_on_landing ?? false;
}catch(e){
console.error(e);
}
// get query params, any param that doesn't start with 'puter.' will be passed to the app
window.app_query_params = {};
for (let [key, value] of window.url_query_params) {
if(!key.startsWith('puter.'))
window.app_query_params[key] = value;
}
}
// --------------------------------------------- // ---------------------------------------------
// Run apps from insta-login URL // Run apps from insta-login URL
// --------------------------------------------- // ---------------------------------------------

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16"><g transform="translate(0, 0)"><path fill-rule="evenodd" clip-rule="evenodd" fill="#ffffff" d="M8,0.2c-4.4,0-8,3.6-8,8c0,3.5,2.3,6.5,5.5,7.6
C5.9,15.9,6,15.6,6,15.4c0-0.2,0-0.7,0-1.4C3.8,14.5,3.3,13,3.3,13c-0.4-0.9-0.9-1.2-0.9-1.2c-0.7-0.5,0.1-0.5,0.1-0.5
c0.8,0.1,1.2,0.8,1.2,0.8C4.4,13.4,5.6,13,6,12.8c0.1-0.5,0.3-0.9,0.5-1.1c-1.8-0.2-3.6-0.9-3.6-4c0-0.9,0.3-1.6,0.8-2.1
c-0.1-0.2-0.4-1,0.1-2.1c0,0,0.7-0.2,2.2,0.8c0.6-0.2,1.3-0.3,2-0.3c0.7,0,1.4,0.1,2,0.3c1.5-1,2.2-0.8,2.2-0.8
c0.4,1.1,0.2,1.9,0.1,2.1c0.5,0.6,0.8,1.3,0.8,2.1c0,3.1-1.9,3.7-3.7,3.9C9.7,12,10,12.5,10,13.2c0,1.1,0,1.9,0,2.2
c0,0.2,0.1,0.5,0.6,0.4c3.2-1.1,5.5-4.1,5.5-7.6C16,3.8,12.4,0.2,8,0.2z"></path></g></svg>

After

Width:  |  Height:  |  Size: 832 B

View File

@ -61,7 +61,7 @@ window.gui = async function(options){
// DEV: Load the initgui.js file if we are in development mode // DEV: Load the initgui.js file if we are in development mode
if(!window.gui_env || window.gui_env === "dev"){ if(!window.gui_env || window.gui_env === "dev"){
await window.loadScript('/sdk/puter.dev.js'); await window.loadScript('/sdk/puter.dev.js');
await window.loadScript(`${options.asset_dir}/initgui.js`, {isModule: true}); // await window.loadScript(`${options.asset_dir}/initgui.js`, {isModule: true});
} }
// PROD: load the minified bundles if we are in production mode // PROD: load the minified bundles if we are in production mode
@ -71,7 +71,6 @@ window.gui = async function(options){
await window.loadScript('https://js.puter.com/v2/'); await window.loadScript('https://js.puter.com/v2/');
// Load the minified bundles // Load the minified bundles
await window.loadCSS('/dist/bundle.min.css'); await window.loadCSS('/dist/bundle.min.css');
await window.loadScript('/dist/bundle.min.js');
} }
// 🚀 Launch the GUI 🚀 // 🚀 Launch the GUI 🚀

View File

@ -46,6 +46,8 @@ import update_mouse_position from './helpers/update_mouse_position.js';
import { LaunchOnInitService } from './services/LaunchOnInitService.js'; import { LaunchOnInitService } from './services/LaunchOnInitService.js';
import item_icon from './helpers/item_icon.js'; import item_icon from './helpers/item_icon.js';
import { AntiCSRFService } from './services/AntiCSRFService.js'; import { AntiCSRFService } from './services/AntiCSRFService.js';
import { IPCService } from './services/IPCService.js';
import { ExecService } from './services/ExecService.js';
const launch_services = async function (options) { const launch_services = async function (options) {
// === Services Data Structures === // === Services Data Structures ===
@ -75,6 +77,8 @@ const launch_services = async function (options) {
globalThis.service_script_api_promise.resolve(service_script_api); globalThis.service_script_api_promise.resolve(service_script_api);
// === Builtin Services === // === Builtin Services ===
register('ipc', new IPCService());
register('exec', new ExecService());
register('broadcast', new BroadcastService()); register('broadcast', new BroadcastService());
register('theme', new ThemeService()); register('theme', new ThemeService());
register('process', new ProcessService()); register('process', new ProcessService());
@ -188,30 +192,7 @@ window.initgui = async function(options){
// will hold the result of the whoami API call // will hold the result of the whoami API call
let whoami; let whoami;
const url_paths = window.location.pathname.split('/').filter(element => element); window.url_paths = window.location.pathname.split('/').filter(element => element);
//--------------------------------------------------------------------------------------
// Determine if an app was launched from URL
// i.e. https://puter.com/app/<app_name>
//--------------------------------------------------------------------------------------
if(url_paths[0]?.toLocaleLowerCase() === 'app' && url_paths[1]){
window.app_launched_from_url = url_paths[1];
// get app metadata
try{
window.app_launched_from_url = await puter.apps.get(window.app_launched_from_url)
window.is_fullpage_mode = window.app_launched_from_url.metadata?.fullpage_on_landing ?? false;
}catch(e){
console.error(e);
}
// get query params, any param that doesn't start with 'puter.' will be passed to the app
window.app_query_params = {};
for (let [key, value] of window.url_query_params) {
if(!key.startsWith('puter.'))
window.app_query_params[key] = value;
}
}
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
// Extract 'action' from URL // Extract 'action' from URL
@ -235,7 +216,6 @@ window.initgui = async function(options){
window.is_fullpage_mode = true; window.is_fullpage_mode = true;
} }
// Launch services before any UI is rendered // Launch services before any UI is rendered
await launch_services(options); await launch_services(options);

View File

@ -0,0 +1,33 @@
import { Service } from "../definitions.js";
import launch_app from "../helpers/launch_app.js";
export class ExecService extends Service {
static description = `
Manages instances of apps on the Puter desktop.
`
async _init ({ services }) {
const svc_ipc = services.get('ipc');
svc_ipc.register_ipc_handler('launchApp', {
handler: this.launchApp.bind(this),
});
}
// This method is exposed to apps via IPCService.
launchApp ({ app_name, args }, { ipc_context, msg_id } = {}) {
// This mechanism will be replated with xdrpc soon
const child_instance_id = window.uuidv4();
window.child_launch_callbacks[child_instance_id] = {
parent_instance_id: event.data.appInstanceID,
launch_msg_id: msg_id,
};
// The "body" of this method is in a separate file
launch_app({
name: app_name,
args: args ?? {},
parent_instance_id: ipc_context?.appInstanceId,
uuid: child_instance_id,
});
}
}

View File

@ -0,0 +1,15 @@
import { Service } from "../definitions.js";
export class IPCService extends Service {
static description = `
Allows other services to expose methods to apps.
`
async _init () {
//
}
register_ipc_handler (name, spec) {
window.ipc_handlers[name] = spec;
}
}

View File

@ -20,10 +20,12 @@ import { encode } from 'html-entities';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import webpack from 'webpack'; import webpack from 'webpack';
import webpack_config from './webpack.config.cjs';
import CleanCSS from 'clean-css'; import CleanCSS from 'clean-css';
import uglifyjs from 'uglify-js'; import uglifyjs from 'uglify-js';
import { lib_paths, css_paths, js_paths } from './src/static-assets.js'; import { lib_paths, css_paths, js_paths } from './src/static-assets.js';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import BaseConfig from './webpack/BaseConfig.cjs';
// Polyfill __dirname, which doesn't exist in modules mode // Polyfill __dirname, which doesn't exist in modules mode
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
@ -128,14 +130,11 @@ async function build(options){
main_array.push(path.join(__dirname, 'src', js_paths[i])); main_array.push(path.join(__dirname, 'src', js_paths[i]));
} }
webpack({ webpack({
...BaseConfig({
...options,
env: 'prod',
}),
mode: 'production', mode: 'production',
entry: {
main: main_array,
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
optimization: { optimization: {
minimize: true, minimize: true,
}, },
@ -147,9 +146,9 @@ async function build(options){
if(options?.verbose) if(options?.verbose)
console.log(stats.toString()); console.log(stats.toString());
// write to ./dist/bundle.min.js // write to ./dist/bundle.min.js
fs.writeFileSync(path.join(__dirname, 'dist', 'bundle.min.js'), icons + '\n\n\n' + js + '\n\n\n' + fs.readFileSync(path.join(__dirname, 'dist', 'main.js'))); // fs.writeFileSync(path.join(__dirname, 'dist', 'bundle.min.js'), fs.readFileSync(path.join(__dirname, 'dist', 'main.js')));
// remove ./dist/main.js // remove ./dist/main.js
fs.unlinkSync(path.join(__dirname, 'dist', 'main.js')); // fs.unlinkSync(path.join(__dirname, 'dist', 'main.js'));
}); });
// Copy index.js to dist/gui.js // Copy index.js to dist/gui.js

View File

@ -0,0 +1,8 @@
const BaseConfig = require('./webpack/BaseConfig.cjs');
module.exports = {
...BaseConfig({ env: 'dev' }),
optimization: {
minimize: false
},
};

View File

@ -0,0 +1,27 @@
const path = require('path');
const EmitPlugin = require('./EmitPlugin.cjs');
module.exports = (options = {}) => {
const config = {};
config.entry = [
'./src/init_sync.js',
'./src/init_async.js',
'./src/initgui.js',
'./src/helpers.js',
'./src/IPC.js',
'./src/globals.js',
'./src/i18n/i18n.js',
'./src/keyboard.js',
'./src/index.js',
];
config.output = {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.min.js',
};
config.plugins = [
EmitPlugin({
options,
dir: path.join(__dirname, '../src/icons'),
}),
];
return config;
};

View File

@ -0,0 +1,78 @@
const fs = require('fs');
const path = require('path');
const uglifyjs = require('uglify-js');
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`;
// -----------------------------------------------
// 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);
if(options?.verbose)
console.log('skipped minification: ', file);
}
js += '\n\n\n';
}
prefix_text += js;
}
// -----------------------------------------------
// 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();
});
};

View File

@ -0,0 +1,15 @@
module.exports = [
"jquery-3.6.1/jquery-3.6.1.min.js",
"viselect.min.js",
"FileSaver.min.js",
"socket.io/socket.io.min.js",
"qrcode.min.js",
"jquery-ui-1.13.2/jquery-ui.min.js",
"lodash@4.17.21.min.js",
"jquery.dragster.js",
"html-entities.js",
"timeago.min.js",
"iro.min.js",
"isMobile.min.js",
"jszip-3.10.1.min.js"
];

View File

@ -20,7 +20,7 @@ import fs from 'fs';
import path_ from 'path'; import path_ from 'path';
import modeString from 'fs-mode-to-string'; import modeString from 'fs-mode-to-string';
import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; import { ErrorCodes, PosixError } from '@heyputer/putility/src/PosixError.js';
// DRY: Almost the same as puter/filesystem.js // DRY: Almost the same as puter/filesystem.js
function wrapAPIs(apis) { function wrapAPIs(apis) {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; import { ErrorCodes, PosixError } from '@heyputer/putility/src/PosixError.js';
// DRY: Almost the same as node/filesystem.js // DRY: Almost the same as node/filesystem.js
function wrapAPIs(apis) { function wrapAPIs(apis) {

View File

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/puter-js-common/src/PosixError.js'; import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/putility/src/PosixError.js';
import { Exit } from './coreutil_lib/exit.js'; import { Exit } from './coreutil_lib/exit.js';
const maxErrorNameLength = Object.keys(ErrorCodes) const maxErrorNameLength = Object.keys(ErrorCodes)

Some files were not shown because too many files have changed in this diff Show More