From e6b2d31a0903aba6e21568bfa3b8f071031800f6 Mon Sep 17 00:00:00 2001 From: jose Date: Mon, 17 Feb 2025 18:37:57 -0300 Subject: [PATCH 01/11] doc: create centralized documentation for developers Developers can easily access documentation on Puter project development concerns, and learn from it in order to contribute to ensure greater usefulness of their work. For the use of it, there are two options: Either the developer runs the mkdocs server locally, or the puter repository can provide a public deployment to access. If you decide that the second case is useful please let me know and I could create a github actions pipeline to deploy this in a separate branch as a static site. Thx for read. --- .gitignore | 3 + doc/dev_doc/docs/arch.md | 153 ++++++ .../docs/deployment/backend_boot_sequence.md | 97 ++++ .../docs/deployment/first-run-issues.md | 57 +++ doc/dev_doc/docs/deployment/self_host.md | 131 +++++ doc/dev_doc/docs/dev_guides/dev_guides.md | 7 + .../docs/dev_guides/making_a_driver.md | 476 ++++++++++++++++++ doc/dev_doc/docs/glosary.md | 28 ++ doc/dev_doc/docs/index.md | 166 ++++++ doc/dev_doc/docs/oscon.md | 127 +++++ doc/dev_doc/docs/roadmap.md | 8 + doc/dev_doc/docs/stack.md | 95 ++++ doc/dev_doc/docs/support.md | 17 + doc/dev_doc/docs/testing/backend_tools.md | 42 ++ doc/dev_doc/docs/this.md | 35 ++ doc/dev_doc/mkdocs.yml | 22 + 16 files changed, 1464 insertions(+) create mode 100644 doc/dev_doc/docs/arch.md create mode 100644 doc/dev_doc/docs/deployment/backend_boot_sequence.md create mode 100644 doc/dev_doc/docs/deployment/first-run-issues.md create mode 100644 doc/dev_doc/docs/deployment/self_host.md create mode 100644 doc/dev_doc/docs/dev_guides/dev_guides.md create mode 100644 doc/dev_doc/docs/dev_guides/making_a_driver.md create mode 100644 doc/dev_doc/docs/glosary.md create mode 100644 doc/dev_doc/docs/index.md create mode 100644 doc/dev_doc/docs/oscon.md create mode 100644 doc/dev_doc/docs/roadmap.md create mode 100644 doc/dev_doc/docs/stack.md create mode 100644 doc/dev_doc/docs/support.md create mode 100644 doc/dev_doc/docs/testing/backend_tools.md create mode 100644 doc/dev_doc/docs/this.md create mode 100644 doc/dev_doc/mkdocs.yml diff --git a/.gitignore b/.gitignore index ab697c25d1..d4d932cc5b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ dist/ # Local Netlify folder .netlify src/emulator/release/ + +# Dinamic dev documentation files +doc/dev_doc/site diff --git a/doc/dev_doc/docs/arch.md b/doc/dev_doc/docs/arch.md new file mode 100644 index 0000000000..57daa64e3a --- /dev/null +++ b/doc/dev_doc/docs/arch.md @@ -0,0 +1,153 @@ +# System Architecture + +## General + +Puter's system goals is to provide an internet operating system, providing (as brief): + +1. **User management:** (User) Account and session CrUD, Permissions... +2. **Desktop environment use:** (User) Use apps in interactive mode through GUIs, CrUD symbolic links and icons... +3. **System deployment:** (Developers) build a web app, or web service, on puter. + +and ensuring: + + 1. **Extensibility:** you should be able to create your own Kernel Modules, user-oriented applications, and so. + 2. **Debuggability:** given this is opensource-driven, you'll find loggers and monitoring tools aiming to make development easier. + 3. **Deployability:** you, and other users, should be able to deploy this system at least both self host and public hosting. + 4. **Securability:** you, and other users, should be able to trust on puter as a personal cloud, a remote desktop for servers and workstations, and as a software development platform. + +In order to achieve those requirements, Puter is following (tl;dr): + +1. **A client-server style Architecture:** Allow user to interact with system GUI through a Web Browser (as an external system). +2. **Micro-kernel pattern:** Allow backend (in which heavy processing occurs) to extend system's functionality, keeping the core of the system and the other additions decoupled each other. + +In in a nutshell: +``` + Puter is Puter, whatever you think it might be useful for + you can use it for. You can think of it as a high-level + operating system where the "hardware" is external services or + resources provided by the host OS; if you develop apps on + this platform you have higher-level primitives, like how + using AI services is considered a "driver", or how Puter's + filesystem can use a database to store the directory tree and + file metadata. +``` + +## Deployment + +### Local dev + +Get the [monorepo](https://github.com/HeyPuter/puter/), and then run `install` and `start` [npm scripts](https://github.com/HeyPuter/puter/blob/main/package.json) + +``` +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +You get in error? then you can [check our first run issues checklist.](./deployment/first-run-issues.md) + +Also, if you get "Cannot write to path" error, it usually happens when /var/puter isn\'t chown\'d to the right UID. You can check the [issue number 645.](https://github.com/HeyPuter/puter/issues/645) +### Docker + +On linux/macOS run: + +``` +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 +``` + +On Windows run: + +``` +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 +``` + +## Main modules traits + +### service + +- **Concern:** to extend core functionality. +- **Class:** BaseService (extends concepts.Service) +- **Public interface:** + +``` +/** +* Creates the service's data structures and initial values. +* This method sets up logging and error handling, and calls a custom `_construct` method if defined. +* +* @returns {Promise} A promise that resolves when construction is complete. +*/ +async construct () => void +``` + +``` +/** +* Constructs service class using Service Resources list +* Service Resources properties: services, config, my_config, name, args, context. +*/ +constructor (service_resources, ...a) +``` + + +``` +/** +* Performs service lifecycle's initialization phase +*/ +async init () => void +``` + +### Kernel + + +- **Concern:** To orchestrate core modules for system to load up, following [**Backend Boot Sequence**.](./deployment/backend_boot_sequence.md) +- **Class:** Kernel (extends AdvancedBase) +- **Public interface:** + +``` +/** +* Construct kernel module configuring its useapi and entry path +*/ +constructor (entry_path) => +``` + + +``` +/** +* Adds a module into kernel's modules list +*/ +add_module (module) => void +``` + +``` +/** +* Boots backend +*/ +boot () => void +``` + +## System entry points + +### Testing +Mocha is being used for this. +There are 2 main **test directories:** +1. src/phoenix/test -> testing phoenix emulator. +2. src/backend/tools/test -> a set of tools for backend testing. [Read more about backend tools.](./testing/backend_tools.md) + +### Use cases +For **self hosting** deployment, there is a _tool_ called "run-selfhosted.js" which you can run with ```npm run start``` command. That tool is going to: + +1. Get all required _kernel modules_ from the **@heyputer/backend npm package** +2. Configure kernel's entry path as the directory path of the current file (so, the run-selfhosted tool's directory). +3. Add all required _kernel modules_ to kernel's modules list. +4. Start kernel by its ```boots()``` public method. + +**Monitoring:** The ```SelfHostedModule``` is responsible for load 3 project's module watching tools (for GUI, TERMINAL, EMULATOR, GIT, PHOENIX, and PUTER-JS) + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/deployment/backend_boot_sequence.md b/doc/dev_doc/docs/deployment/backend_boot_sequence.md new file mode 100644 index 0000000000..91a28b6e47 --- /dev/null +++ b/doc/dev_doc/docs/deployment/backend_boot_sequence.md @@ -0,0 +1,97 @@ +# Puter Backend Boot Sequence + +This document describes the boot sequence of Puter's backend. + +**Runtime Environment** + - Configuration directory is determined + - Runtime directory is determined + - Mod directory is determined + - Services are instantiated + +**Construction** + - Data structures are created + +**Initialization** + - Registries are populated + - Services prepare for next phase + +**Consolidation** + - Service event bus receives first event (`boot.consolidation`) + - Services perform coordinated setup behaviors + - Services prepare for next phase + +**Activation** + - Blocking listeners of `boot.consolidation` have resolved + - HTTP servers start listening + +**Ready** + - Services are informed that Puter is providing service + +## Boot Phases + +### Construction + +Services implement a method called `construct` which initializes members +of an instance. Services do not override the class constructor of +**BaseService**. This makes it possible to use the `new` operator without +invoking a service's constructor behavior during debugging. + +The first phase of the boot sequence, "construction", is simply a loop to +call `construct` on all registered services. + +The `_construct` override should not: +- call other services +- emit events + +### Initialization + +At initialization, the `init()` method is called on all services. +The `_init` override can be used to: +- register information with other services, when services don't + need to register this information in a specific sequence. + An example of this is registering commands with CommandService. +- perform setup that is required before the consolidation phase starts. + +### Consolidation + +Consolidation is a phase where services should emit events that +are related to bringing up the system. For example, WebServerService +('web-server') emits an event telling services to install middlewares, +and later emits an event telling services to install routes. + +Consolidation starts when Kernel emits `boot.consolidation` to the +services event bus, which happens after `init()` resolves for all +services. + +### Activation + +Activation is a phase where services begin listening on external +interfaces. For example, this is when the web server starts listening. + +Activation starts when Kernel emits `boot.activation`. + +### Ready + +Ready is a phase where services are informed that everything is up. + +Ready starts when Kernel emits `boot.ready`. + +## Events and Asynchronous Execution + +The services event bus is implemented so you can `await` a call to `.emit()`. +Event listeners can choose to have blocking behavior by returning a promise. + +During emission of a particular event, listeners of this event will not +block each other, but all listeners must resolve before the call to +`.emit()` is resolved. (i.e. `emit` uses `Promise.all`) + +## Legacy Services + +Some services were implemented before the `BaseService` class - which +implements the `init` method - was created. These services are called +"legacy services" and they are instantiated _after_ initialization but +_before_ consolidation. + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/deployment/first-run-issues.md b/doc/dev_doc/docs/deployment/first-run-issues.md new file mode 100644 index 0000000000..dc12e6adcd --- /dev/null +++ b/doc/dev_doc/docs/deployment/first-run-issues.md @@ -0,0 +1,57 @@ +# First Run Issues + +## "Cannot find package '@heyputer/backend'" + +Scenario: You see the following output: + +``` +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Cannot find package '@heyputer/backend' ┃ +┃ 📝 this usually happens if you forget `npm install` ┃ +┃ Suggestions: ┃ +┃ - try running `npm install` ┃ +┃ Technical Notes: ┃ +┃ - @heyputer/backend is in an npm workspace ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ +``` + +1. Ensure you have run `npm install`. +2. [Install build essentials for your distro](#installing-build-essentials), + then run `npm install` again. + +## Installing Build Essentials + +### Debian-based distros + +``` +sudo apt update +sudo apt install build-essential +``` + +### RHEL-family distros (Fedora, Rocky, etc) + +``` +sudo dnf groupinstall "Development Tools" +``` + +### "I use Arch btw" + +``` +sudo pacman -S base-devel +``` + +### Alpine + +If you're running in Puter's Alpine image then this is already installed. + +``` +sudo apk add build-base +``` + +### Gentoo + +You know what you're doing; you just wanted to see if we mentioned Gentoo. + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/deployment/self_host.md b/doc/dev_doc/docs/deployment/self_host.md new file mode 100644 index 0000000000..f7b1201b0e --- /dev/null +++ b/doc/dev_doc/docs/deployment/self_host.md @@ -0,0 +1,131 @@ +# Self-Hosting Puter + +> [!WARNING] +> The self-hosted version of Puter is currently in alpha stage and should not be used in production yet. It is under active development and may contain bugs, other issues. Please exercise caution and use it for testing and evaluation purposes only. + +### Self-Hosting Differences +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 access apps from puter.com (see below) +- Several "core" apps are missing, such as **Code** or **Draw** +- Some assets are different + +Work is ongoing to improve the **App Center** and make it available on self-hosted. +Until then, it is still possible to add apps using the **Dev Center** app. + +
+ +## Configuration + +Running the server will generate a configuration file in one of these locations: +- `config/config.json` when [Using Docker](#using-docker) +- `volatile/config/config.json` in [Local Development](#local-development) +- `/etc/puter/config.json` on a server (or within a Docker container) + +### Domain Name + +To access Puter on your device, you can simply go to the address printed in +the server console (usually `puter.localhost:4100`). + +To access Puter from another device, a domain name must be configured, as well as +an `api` subdomain. For example, `example.local` might be the domain name pointing +to the IP address of the server running puter, and `api.example.com` must point to +this address as well. This domain must be specified in the configuration file +(usually `volatile/config/config.json`) as well. + +See [domain configuration](#configuring-domains-for-self-hosted-puter) for more information. + +### Configure the Port + +- You can specify a custom port by setting `http_port` to a desired value +- If you're using a reverse-proxy such as nginx or cloudflare, you should + also set `pub_port` to the public (external) port (usually `443`) +- If you have HTTPS enabled on your reverse-proxy, ensure that + `protocol` in config.json is set accordingly + +### Default User + +By default, Puter will create a user called `default_user`. +This user will have a randomly generated password, which will be printed +in the development console. +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 +your first step. + +
+ +## Configuring Domains for Self-Hosted Puter + +### Local Network Configuration + +#### Prerequisite Conditions + +Ensure the hosting device has a static IP address to prevent potential connectivity issues due to IP changes. This setup will enable seamless access to Puter and its services across your local network. + +#### Using Hosts Files + +The hosts file is a straightforward way to map domain names to IP addresses on individual devices. It's simple to set up but requires manual changes on each device that needs access to the domains. + +##### Windows +1. Open Notepad as an administrator. +2. Open the file located at `C:\Windows\System32\drivers\etc\hosts`. +3. Add lines for your domain and subdomain with the server's IP address, in the + following format: + ``` + 192.168.1.10 puter.local + 192.168.1.10 api.puter.local + ``` + +##### For macOS and Linux: +1. Open a terminal. +2. Edit the hosts file with a text editor, e.g., `sudo nano /etc/hosts`. +3. Add lines for your domain and subdomain with the server's IP address, in the + following format: + ``` + 192.168.1.10 puter.local + 192.168.1.10 api.puter.local + ``` +4. Save and exit the editor. + + +#### Using Router Configuration + +Some routers allow you to add custom DNS rules, letting you configure domain names network-wide without touching each device. + +1. Access your router’s admin interface (usually through a web browser). +2. Look for DNS or DHCP settings. +3. Add custom DNS mappings for `puter.local` and `api.puter.local` to the hosting device's IP address. +4. Save the changes and reboot the router if necessary. + +This method's availability and steps may vary depending on your router's model and firmware. + +#### Using Local DNS + +Setting up a local DNS server on your network allows for flexible and scalable domain name resolution. This method works across all devices automatically once they're configured to use the DNS server. + +##### Options for DNS Software: + +- **Pi-hole**: Acts as both an ad-blocker and a DNS server. Ideal for easy setup and maintenance. +- **BIND9**: Offers comprehensive DNS server capabilities for complex setups. +- **dnsmasq**: Lightweight and suitable for smaller networks or those new to running a DNS server. + +**contributors note:** feel free to add any software you're aware of +which might help with this to the list. Also, feel free to add instructions here for specific software; our goal is for Puter to be easy to setup with tools you're already familiar with. + +##### General Steps: + +1. Choose and install DNS server software on a device within your network. +2. Configure the DNS server to resolve `puter.local` and `api.puter.local` to the IP address of your Puter hosting device. +3. Update your router's DHCP settings to distribute the DNS server's IP address to all devices on the network. + +By setting up a local DNS server, you gain the most flexibility and control over your network's domain name resolution, ensuring that all devices can access Puter and its API without manual configuration. + +### Production Configuration + +Please note the self-hosting feature is still in alpha and a public production +deployment is not recommended at this time. However, if you wish to host +publicly you can do so following the same steps you normally would to configure +a domain name and ensuring the `api` subdomain points to the server as well. + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/dev_guides/dev_guides.md b/doc/dev_doc/docs/dev_guides/dev_guides.md new file mode 100644 index 0000000000..6d3e9d827a --- /dev/null +++ b/doc/dev_doc/docs/dev_guides/dev_guides.md @@ -0,0 +1,7 @@ +# Dev guides + +This is a collection of development guides that follow the practices, tools and conventions of the project. + +1. [How to make a driver.](./making_a_driver.md) +> There is also a [video from Eric on this](https://www.youtube.com/watch?v=8znQmrKgNxA) +2. [Passing argumentos to phoenix shell](https://www.youtube.com/watch?v=VDPu7hwBsq8) diff --git a/doc/dev_doc/docs/dev_guides/making_a_driver.md b/doc/dev_doc/docs/dev_guides/making_a_driver.md new file mode 100644 index 0000000000..47d77aeb45 --- /dev/null +++ b/doc/dev_doc/docs/dev_guides/making_a_driver.md @@ -0,0 +1,476 @@ +# How to Make a Puter Driver + +## What is a Driver? + +A driver can be one of two things depending on what you're +talking about: +- a **driver interface** describes a general type of service + and what its parameters and result look like. + For example, `puter-chat-completion` is a driver interface + for AI Chat services, and it specifies that any service + on Puter for AI Chat needs a method called `complete` that + accepts a JSON parameter called `messages`. +- a **driver implementation** exists when a **Service** on + Puter implements a **trait** with the same name as a + driver interface. + +## Part 1: Choose or Create a Driver Interface + +Available driver interfaces exist at this location in the repo: +[/src/backend/src/services/drivers/interfaces.js](../src/services/drivers/interfaces.js). + +When creating a new Puter driver implementation, you should check +this file to see if there's an appropriate interface. We're going +to make a driver that returns greeting strings, so we can use the +existing `hello-world` interface. If there wasn't an existing +interface, it would need to be created. Let's break down this +interface: + +```javascript +'hello-world': { + description: 'A simple driver that returns a greeting.', + methods: { + greet: { + description: 'Returns a greeting.', + parameters: { + subject: { + type: 'string', + optional: true, + }, + }, + result: { type: 'string' }, + } + } +}, +``` + +The **description** describes what the interface is for. This +should be provided that both driver developers and users can +quickly identify what types of services should use it. + +The **methods** object should have at least one entry, but it +may have more. The key of each entry is the name of a method; +in here we see `greet`. Each method also has a description, +a **parameters** object, and a **result** object. + +The **parameters** object has an entry for each parameter that +may be passed to the method. Each entry is an object with a +`type` property specifying what values are allowed, and possibly +an `optional: true` entry. + +All methods for Puter drivers use _named parameters_. There are no +positional parameters in Puter driver methods. + +The **result** object specifies the type of the result. A service +called DriverService will use this to determine the response format +and headers of the response. + +## Part 2: Create a Service + +Creating a service is very easy, provided the service doesn't do +anything. Simply add a class to `src/backend/src/services` or into +the module of your choice (`src/backend/src/modules/`) +that looks like this: + +```javascript +const BaseService = require('./BaseService') +// NOTE: the path specified ^ HERE might be different depending +// on the location of your file. + +class PrankGreetService extends BaseService { +} +``` + +Notice I called the service "PrankGreet". This is a good service +name because you already know what the service is likely to +implement: this service generates a greeting, but it is a greeting +that intends to play a prank on whoever is beeing greeted. + +Then, register the service into a module. If you put the service +under `src/backend/src/services`, then it goes in +[CoreModule](..//src/CoreModule.js) somewhere near the end of +the `install()` method. Otherwise, it will go in the `*Module.js` +file in the module where you placed your service. + +The code to register the service is two lines of code that will +look something like this: + +```javascript +const { PrankGreetServie } = require('./path/to/PrankGreetServie.js'); +services.registerService('prank-greet', PrankGreetServie); +``` + +## Part 3: Verify that the Service is Registered + +It's always a good idea to verify that the service is loaded +when starting Puter. Otherwise, you might spend time trying to +determine why your code doesn't work, when in fact it's not +running at all to begin with. + +To do this, we'll add an `_init` handler to the service that +logs a message after a few seconds. We wait a few seconds so that +any log noise from boot won't bury our message. + +```javascript +class PrankGreetService extends BaseService { + async _init () { + // Wait for 5 seconds + await new Promise(rslv => setTimeout(rslv), 5000); + + // Display a log message + this.log.noticeme('Hello from PrankGreetService!'); + } +} +``` + +Typically you'll use `this.log.info('some message')` in your logs +as opposed to `this.log.noticeme(...)`, but the `noticeme` log +level is helpful when debugging. + +## Part 4: Implement the Driver Interface in your Service + +Now that it has been verified that the service is loaded, we can +start implementing the driver interface we chose eralier. + +```javascript +class PrankGreetService extends BaseService { + async _init () { + // ... same as before + } + + // Now we add this: + static IMPLEMENTS = { + ['hello-world']: { + async greet ({ subject }) { + if ( subject ) { + return `Hello ${subject}, tell me about updog!`; + } + return `Hello, tell me about updog!`; + } + } + } +} +``` + +## Part 5: Test the Driver Implementation + +We have now created the `prank-greet` implementation of `hello-world`. +Let's make a request in the browser to check it out. The example below +is a `fetch` call using `http://api.puter.localhost:4100` as the API +origin, which is the default when you're running Puter's backend locally. + +Also, in this request I refer to `puter.authToken`. If you run this +snippet in the Dev Tools window of your browser from a tab with Puter +open (your local Puter, to be precise), this should contain the current +value for your auth token. + +```javascript +await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'hello-world', + service: 'prank-greet', + method: 'greet', + args: { + subject: 'World', + }, + }), + "method": "POST", +})).json(); +``` + +**You might see a permissions error!** Don't worry, this is expected; +in the next step we'll add the required permissions. + +## Part 6: Permissions + +In the previous step, you will only have gotten a successful response +if you're logged in as the `admin` user. If you're logged in as another +user you won't have access to the service's driver implementations be +default. + +To grant permission for all users, update +[hardcoded-permissions.js](../src/data/hardcoded-permissions.js). + +First, look for the constant `hardcoded_user_group_permissions`. +Whereever you see an entry for `service:hello-world:ii:hello-world`, add +the corresponding entry for your service, which will be called +``` +service:prank-greet:ii:hello-world +``` + +To help you remember the permission string, its helpful to know that +`ii` in the string stands for "invoke interface". i.e. the scope of the +permission is under `service:prank-greet` (the `prank-greet` service) +and we want permission to invoke the interface `hello-world` on that +service. + +You'll notice each entry in `hardcoded_user_group_permissions` has a value +determined by a call to the utility function `policy_perm(...)`. The policy +called `user.es` is a permissive policy for storage drivers, and we can +re-purpose it for our greeting implementor. + +The policy of a permission determines behavior like rate limiting. This is +an advanced topic that is not covered in this guide. + +If you want apps to be able to access the driver implementation without +explicit permission from a user, you will need to also register it in the +`default_implicit_user_app_permissions` constant. Additionally, you can +use the `implicit_user_app_permissions` constant to grant implicit +permission to the builtin Puter apps only. + +Permissions to implementations on services can also be granted at runtime +to a user or group of users using the permissions API. This is beyond the +scope of this guide. + +## Part 7: Verify Successful Response + +If all went well, you should see the response in your console when you +try the request from Part 5. Try logging into a user other than `admin` +to verify permisison is granted. + +```json +"Hello World, tell me about updog!" +``` How to Make a Puter Driver + +## What is a Driver? + +A driver can be one of two things depending on what you're +talking about: +- a **driver interface** describes a general type of service + and what its parameters and result look like. + For example, `puter-chat-completion` is a driver interface + for AI Chat services, and it specifies that any service + on Puter for AI Chat needs a method called `complete` that + accepts a JSON parameter called `messages`. +- a **driver implementation** exists when a **Service** on + Puter implements a **trait** with the same name as a + driver interface. + +## Part 1: Choose or Create a Driver Interface + +Available driver interfaces exist at this location in the repo: +[/src/backend/src/services/drivers/interfaces.js](../src/services/drivers/interfaces.js). + +When creating a new Puter driver implementation, you should check +this file to see if there's an appropriate interface. We're going +to make a driver that returns greeting strings, so we can use the +existing `hello-world` interface. If there wasn't an existing +interface, it would need to be created. Let's break down this +interface: + +```javascript +'hello-world': { + description: 'A simple driver that returns a greeting.', + methods: { + greet: { + description: 'Returns a greeting.', + parameters: { + subject: { + type: 'string', + optional: true, + }, + }, + result: { type: 'string' }, + } + } +}, +``` + +The **description** describes what the interface is for. This +should be provided that both driver developers and users can +quickly identify what types of services should use it. + +The **methods** object should have at least one entry, but it +may have more. The key of each entry is the name of a method; +in here we see `greet`. Each method also has a description, +a **parameters** object, and a **result** object. + +The **parameters** object has an entry for each parameter that +may be passed to the method. Each entry is an object with a +`type` property specifying what values are allowed, and possibly +an `optional: true` entry. + +All methods for Puter drivers use _named parameters_. There are no +positional parameters in Puter driver methods. + +The **result** object specifies the type of the result. A service +called DriverService will use this to determine the response format +and headers of the response. + +## Part 2: Create a Service + +Creating a service is very easy, provided the service doesn't do +anything. Simply add a class to `src/backend/src/services` or into +the module of your choice (`src/backend/src/modules/`) +that looks like this: + +```javascript +const BaseService = require('./BaseService') +// NOTE: the path specified ^ HERE might be different depending +// on the location of your file. + +class PrankGreetService extends BaseService { +} +``` + +Notice I called the service "PrankGreet". This is a good service +name because you already know what the service is likely to +implement: this service generates a greeting, but it is a greeting +that intends to play a prank on whoever is beeing greeted. + +Then, register the service into a module. If you put the service +under `src/backend/src/services`, then it goes in +[CoreModule](..//src/CoreModule.js) somewhere near the end of +the `install()` method. Otherwise, it will go in the `*Module.js` +file in the module where you placed your service. + +The code to register the service is two lines of code that will +look something like this: + +```javascript +const { PrankGreetServie } = require('./path/to/PrankGreetServie.js'); +services.registerService('prank-greet', PrankGreetServie); +``` + +## Part 3: Verify that the Service is Registered + +It's always a good idea to verify that the service is loaded +when starting Puter. Otherwise, you might spend time trying to +determine why your code doesn't work, when in fact it's not +running at all to begin with. + +To do this, we'll add an `_init` handler to the service that +logs a message after a few seconds. We wait a few seconds so that +any log noise from boot won't bury our message. + +```javascript +class PrankGreetService extends BaseService { + async _init () { + // Wait for 5 seconds + await new Promise(rslv => setTimeout(rslv), 5000); + + // Display a log message + this.log.noticeme('Hello from PrankGreetService!'); + } +} +``` + +Typically you'll use `this.log.info('some message')` in your logs +as opposed to `this.log.noticeme(...)`, but the `noticeme` log +level is helpful when debugging. + +## Part 4: Implement the Driver Interface in your Service + +Now that it has been verified that the service is loaded, we can +start implementing the driver interface we chose eralier. + +```javascript +class PrankGreetService extends BaseService { + async _init () { + // ... same as before + } + + // Now we add this: + static IMPLEMENTS = { + ['hello-world']: { + async greet ({ subject }) { + if ( subject ) { + return `Hello ${subject}, tell me about updog!`; + } + return `Hello, tell me about updog!`; + } + } + } +} +``` + +## Part 5: Test the Driver Implementation + +We have now created the `prank-greet` implementation of `hello-world`. +Let's make a request in the browser to check it out. The example below +is a `fetch` call using `http://api.puter.localhost:4100` as the API +origin, which is the default when you're running Puter's backend locally. + +Also, in this request I refer to `puter.authToken`. If you run this +snippet in the Dev Tools window of your browser from a tab with Puter +open (your local Puter, to be precise), this should contain the current +value for your auth token. + +```javascript +await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'hello-world', + service: 'prank-greet', + method: 'greet', + args: { + subject: 'World', + }, + }), + "method": "POST", +})).json(); +``` + +**You might see a permissions error!** Don't worry, this is expected; +in the next step we'll add the required permissions. + +## Part 6: Permissions + +In the previous step, you will only have gotten a successful response +if you're logged in as the `admin` user. If you're logged in as another +user you won't have access to the service's driver implementations be +default. + +To grant permission for all users, update +[hardcoded-permissions.js](../src/data/hardcoded-permissions.js). + +First, look for the constant `hardcoded_user_group_permissions`. +Whereever you see an entry for `service:hello-world:ii:hello-world`, add +the corresponding entry for your service, which will be called +``` +service:prank-greet:ii:hello-world +``` + +To help you remember the permission string, its helpful to know that +`ii` in the string stands for "invoke interface". i.e. the scope of the +permission is under `service:prank-greet` (the `prank-greet` service) +and we want permission to invoke the interface `hello-world` on that +service. + +You'll notice each entry in `hardcoded_user_group_permissions` has a value +determined by a call to the utility function `policy_perm(...)`. The policy +called `user.es` is a permissive policy for storage drivers, and we can +re-purpose it for our greeting implementor. + +The policy of a permission determines behavior like rate limiting. This is +an advanced topic that is not covered in this guide. + +If you want apps to be able to access the driver implementation without +explicit permission from a user, you will need to also register it in the +`default_implicit_user_app_permissions` constant. Additionally, you can +use the `implicit_user_app_permissions` constant to grant implicit +permission to the builtin Puter apps only. + +Permissions to implementations on services can also be granted at runtime +to a user or group of users using the permissions API. This is beyond the +scope of this guide. + +## Part 7: Verify Successful Response + +If all went well, you should see the response in your console when you +try the request from Part 5. Try logging into a user other than `admin` +to verify permisison is granted. + +```json +"Hello World, tell me about updog!" + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/glosary.md b/doc/dev_doc/docs/glosary.md new file mode 100644 index 0000000000..89fbf2cd50 --- /dev/null +++ b/doc/dev_doc/docs/glosary.md @@ -0,0 +1,28 @@ +# Puter's glosary + +## General + +1. **Puter:** Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. + +2. **Self hosting:** Means running and managing the app on your infrastructure instead of using thid-party hosting service. +You can learn more on how to self host your Puter instance [here](./deployment/self_host.md) + +3. **Kernel:** It is a simple module which is in charge of orchestrating the initialization of the system, following the boot sequence. Following the [Microkernel pattern](https://www.oreilly.com/library/view/software-architecture-patterns/9781098134280/ch04.html), this module corresponds to the Core of Puter backend. + +4. **Monorepo:** A centralised source code repository made of several interrelated packages. + +5. **npm workspace:** An NPM workspace is a NPM feature that allows you to **manage multiple related packages** (like a monorepo) within a single repository. + +## Backend components + +1. **BasicBase:** Abstract class with inheritance tracking for composite the system using shared configuration and behaviors. +2. **FeatureBase:** Extending BasicBase, allows defining and install features (classes and modules) as TopicsFeature, MariMethodsfeature, and others. +3. **AdvancedBase:** Extending FeatureBase, Defines features to be installed by Its FeatureBase parent instance. + +> As you can see, components follows an inheritance chain which starts in BasicBase. + +4. **KernelModule:** Extending AdvancedBase, orchestrate system boot sequence. + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/index.md b/doc/dev_doc/docs/index.md new file mode 100644 index 0000000000..be97eb1a78 --- /dev/null +++ b/doc/dev_doc/docs/index.md @@ -0,0 +1,166 @@ +

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

+ +

The Internet OS! Free, Open-Source, and Self-Hostable.

+ +

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + CLI + · + Discord + · + Reddit + · + X +

+ +

screenshot

+ +
+ +## Puter + +Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. Puter can be used as: + +- A privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time. +- A platform for building and publishing websites, web apps, and games. +- An alternative to Dropbox, Google Drive, OneDrive, etc. with a fresh interface and powerful features. +- A remote desktop environment for servers and workstations. +- A friendly, open-source project and community to learn about web development, cloud computing, distributed systems, and much more! + +
+ +## Getting Started + +### 💻 Local Development + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +This will launch Puter at http://puter.localhost:4100 (or the next available port). + +If this does not work, see [First Run Issues](./doc/first-run-issues.md) for +troubleshooting steps. + +
+ +### 🐳 Docker + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ +### 🐙 Docker Compose + +#### Linux/macOS + +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` + +
+ +#### Windows + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` + +
+ +### 🚀 Self-Hosting + +For detailed guides on self-hosting Puter, including configuration options and best practices, see our [Self-Hosting Documentation](https://github.com/HeyPuter/puter/blob/main/doc/self-hosters/instructions.md). + +
+ +### ☁️ Puter.com + +Puter is available as a hosted service at [**puter.com**](https://puter.com). + +
+ +## System Requirements + +- **Operating Systems:** Linux, macOS, Windows +- **RAM:** 2GB minimum (4GB recommended) +- **Disk Space:** 1GB free space +- **Node.js:** Version 16+ (Version 22+ recommended) +- **npm:** Latest stable version + +
+ +## Support + +Connect with the maintainers and community through these channels: + +- Bug report or feature request? Please [open an 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) +- Security issues? [security@puter.com](mailto:security@puter.com) +- Email maintainers at [hi@puter.com](mailto:hi@puter.com) + +We are always happy to help you with any questions you may have. Don't hesitate to ask! + +
+ +## License + +This repository, including all its contents, sub-projects, modules, and components, is licensed under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses. + +
+ +## Translations + +- [Arabic / العربية](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ar.md) +- [Armenian / Հայերեն](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hy.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) +- [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) +- [English](https://github.com/HeyPuter/puter/blob/main/README.md) +- [Farsi / فارسی](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fa.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) +- [German/ Deutsch](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.de.md) +- [Hebrew/ עברית](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.he.md) +- [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) +- [Hungarian / Magyar](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hu.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) +- [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) +- [Malayalam / മലയാളം](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ml.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) +- [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) +- [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) +- [Swedish / Svenska](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.sv.md) +- [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) +- [Telugu / తెలుగు](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.te.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) +- [Ukrainian / Українська](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ua.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) diff --git a/doc/dev_doc/docs/oscon.md b/doc/dev_doc/docs/oscon.md new file mode 100644 index 0000000000..477566a97d --- /dev/null +++ b/doc/dev_doc/docs/oscon.md @@ -0,0 +1,127 @@ +# Contributing to Puter + +Welcome to Puter, the open-source distributed internet operating system. We're excited to have you contribute to our project, whether you're reporting bugs, suggesting new features, or contributing code. This guide will help you get started with contributing to Puter in different ways. + +
+ +# Report bugs + +Before reporting a bug, please check our [the issues on our GitHub repository](https://github.com/HeyPuter/puter/issues) to see if the bug has already been reported. If it has, you can add a comment to the existing issue with any additional information you have. + +If you find a new bug in Puter, please [open an issue on our GitHub repository](https://github.com/HeyPuter/puter/issues/new). We'll do our best to address the issue as soon as possible. When reporting a bug, please include as much information as possible, including: + +- A clear and descriptive title +- A description of the issue +- Steps to reproduce the bug +- Expected behavior +- Actual behavior +- Screenshots, if applicable +- Your host operating system and browser +- Your Puter version, location, ... + +Please open a separate issue for each bug you find. + +Maintainers will apply the appropriate labels to your issue. + +
+ +# Suggest new features + +If you have an idea for a new feature in Puter, please open a new discussion thread on our [GitHub repository](https://github.com/HeyPuter/puter/discussions) to discuss your idea with the community. We'll do our best to respond to your suggestion as soon as possible. + +When suggesting a new feature, please include as much information as possible, including: + +- A clear and descriptive title +- A description of the feature +- The problem the feature will solve +- Any relevant screenshots or mockups +- Any relevant links or resources + +
+ +# Contribute code + +If you'd like to contribute code to Puter, you need to fork the project and submit a pull request. If this is your first time contributing to an open-source project, we recommend reading this short guide by GitHub on [how to contribute to a project](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project). + +We'll review your pull request and work with you to get your changes merged into the project. + +## Repository Structure + +![file structure](./doc/File%20Structure.drawio.png) + +## Your first code contribution + +We maintain a list of issues that are good for first-time contributors. You can find these issues by searching for the [`good first issue`](https://github.com/HeyPuter/puter/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label in our [GitHub repository](https://github.com/HeyPuter/puter). These issues are designed to be relatively easy to fix, and we're happy to help you get started. Pick an issue that interests you, and leave a comment on the issue to let us know you're working on it. + +## Documentation for Contributors + +### Backend +See [src/backend/CONTRIBUTING.md](src/backend/CONTRIBUTING.md) + +
+ +## 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) + +
+ +## Commit Messages + +**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. + +### Conventional Commits +We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) with the following prefixes: +- `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: +- If the commit message is in _past tense_, it's a shorthand for the following: + - `dev: apply changes that would be applied after one had ` +- If the commit message is in _present tense_, it's shorthand for the following: + - `dev: apply changes that would be applied after ` + +For example, the following are correct: +- `dev: improved readdir` + - interpret this as: `dev: apply changes that would be applied after one had improved readdir` +- `dev: improving readdir` + - interpret this as: `dev: apply changes that would be applied after improving readdir` + +
+ +## Code Review + +Once you've submitted your pull request, the project maintainers will review your changes. We may suggest some changes or improvements. This is a normal part of the process, and your contributions are greatly appreciated! + +
+ +## Contribution License Agreement (CLA) + +Like many open source projects, we require contributors to sign a Contribution License Agreement (CLA) before we can accept your code. When you open a pull request for the first time, a bot will automatically add a comment with a link to the CLA. You can sign the CLA electronically by following the link and filling out the form. + +
+ +# Getting Help + +If you have any questions about Puter, please feel free to reach out to us through the following channels: + +- [Discord](https://discord.com/invite/PQcx7Teh8u) +- [Reddit](https://www.reddit.com/r/Puter/) +- [Twitter](https://twitter.com/HeyPuter) +- [Email](mailto:support@puter.com) + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/roadmap.md b/doc/dev_doc/docs/roadmap.md new file mode 100644 index 0000000000..05e60bd8f1 --- /dev/null +++ b/doc/dev_doc/docs/roadmap.md @@ -0,0 +1,8 @@ +# What next? + +This is a project under development with current working releases [check our changelog.](https://github.com/HeyPuter/puter/releases/) +This documentation is under development too, and you could improve it with your pr. + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/stack.md b/doc/dev_doc/docs/stack.md new file mode 100644 index 0000000000..a2dabb1997 --- /dev/null +++ b/doc/dev_doc/docs/stack.md @@ -0,0 +1,95 @@ +# Stack of puter + +Puter source is modular, meaning that there are a **node module for each src/ folder subdirectory**. +That means each module could be defining its own package dependency list. + +## General + +1. Using Javascript as main language. +2. Using DHTML (html,js,css) for dinamic web rendering. +3. Using Shell and Docker for building and deployment scripts. +4. Using Docker for containerized deployment. +5. Using SQLITE for persistence (of sessions, app storage...) +6. Using local disk for some storage operations. + +## Node related + +Puter currently Node-related stack is: + +### DevDependencies + +1. **[@eslint/js](https://eslint.org/docs/latest/)** + Official ESLint extension to handle JavaScript specific rules. + +2. **[chalk](https://github.com/chalk/chalk)** + Allows formating terminal output with colors and styles. + +3. **[clean-css](https://github.com/clean-css/clean-css)** + Efficient CSS minifier. + +4. **[dotenv](https://github.com/motdotla/dotenv#readme)** + Load environment variables from a `.env` file into `process.env`. + +5. **[eslint](https://eslint.org/docs/latest/)** + Static analysis tool to find and fix problems in JavaScript code. + +6. **[express](https://expressjs.com/)** + Minimalistic framework for building web applications in Node.js. + +7. **[globals](https://github.com/sindresorhus/globals#readme)** + List of global variables recognized in different environments. + +8. **[html-entities](https://github.com/mdevils/html-entities#readme)** + Encodes and decodes HTML entities in JavaScript. + +9. **[html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin#readme)** + Automatically generates HTML files for Webpack projects. + +10. **[license-check-and-add](https://github.com/mjhenkes/license-check-and-add#readme)** + Automatically checks and adds licenses to project files. + +11. **[mocha](https://mochajs.org/)** + JavaScript testing framework with support for asynchronous testing. + +12. **[nodemon](https://github.com/remy/nodemon#readme)** + Automatically reloads a Node.js application when it detects code changes. + +13. **[uglify-js](https://github.com/mishoo/UglifyJS#readme)** + Minifies and optimizes JavaScript code to reduce its size. + +14. **[webpack](https://webpack.js.org/)** + Module packer for JavaScript. + +### Dependencies + +16. **[javascript-time-ago](https://github.com/catamphetamine/javascript-time-ago#readme)** + Friendly formatting of dates and times in different languages. + +17. **[json-colorizer](https://github.com/kaelzhang/node-json-colorizer#readme)** + Format and colorize JSON output in the terminal. + +18. **[open](https://github.com/sindresorhus/open#readme)** + Opens default URLs, files or applications from Node.js. + +19. **[sharp](https://sharp.pixelplumbing.com/)** + Fast and optimized image processing library for Node.js. + +20. **[sharp-bmp](https://github.com/karaggeorge/sharp-bmp#readme)** + Sharp extension to handle BMP images. + +21. **[sharp-ico](https://github.com/karaggeorge/sharp-ico#readme)** + Sharp extension to handle ICO images. + +22. **[simple-git](https://github.com/steveukx/git-js#readme)** + Simple interface to work with Git in Node.js. + +23. **[string-template](https://github.com/Matt-Esch/string-template#readme)** + Simple string-based template engine. + +24. **[uuid](https://github.com/uuidjs/uuid#readme)** + Unique generator of UUID identifiers according to RFC standards. + + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/support.md b/doc/dev_doc/docs/support.md new file mode 100644 index 0000000000..3f5d2ac4ad --- /dev/null +++ b/doc/dev_doc/docs/support.md @@ -0,0 +1,17 @@ +# Support + +Connect with the maintainers and community through these official channels: + +- Bug report or feature request? Please [open an 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) +- Security issues? [security@puter.com](mailto:security@puter.com) +- Email maintainers at [hi@puter.com](mailto:hi@puter.com) + +We are always happy to help you with any questions you may have. Don't hesitate to ask! + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/testing/backend_tools.md b/doc/dev_doc/docs/testing/backend_tools.md new file mode 100644 index 0000000000..ffefc80834 --- /dev/null +++ b/doc/dev_doc/docs/testing/backend_tools.md @@ -0,0 +1,42 @@ +# Backend Tools Directory + +## Test Kernel + +The **Test Kernel** is a drop-in replacement for Puter's main kernel. Instead of +actually initializing and running services, it only registers them and then invokes +a test iterator through all the services. + +The Test Kernel is ideal for running unit and integration tests against individual services, ensuring they behave correctly. + +### Test Kernel Notes + +1. **Logging**: + A custom `TestLogger` is provided for simplified logging output during tests. + Since LogService is never initialized, this is never replaced. + +2. **Context Management**: + The Test Kernel uses the same `Context` system as the main Kernel. This gives test environments a consistent way to access global state, configuration, and service containers. + +3. **Assertion & Results Tracking**: + The Test Kernel includes a simple testing structure that: + - Tracks passed and failed assertions. + - Repeats assertion outputs at the end of test runs for clarity. + - Allows specifying which services to test via command-line arguments. + +### Typical Workflow + +1. **Initialization**: + Instantiate the Test Kernel, and add any modules you want to test. + +2. **Module Installation**: + The Test Kernel installs these modules (via `_install_modules()`), making their services available in the `Container`. + +3. **Service Testing**: + After modules are installed, each service can be constructed and tested. Tests are implemented as `_test()` methods on services, using simple assertion helpers (`testapi.assert` and `testapi.assert.equal`). + +4. **Result Summarization**: + Once all tests run, the Test Kernel prints a summary of passed and failed assertions, aiding quick evaluation of test outcomes. + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/this.md b/doc/dev_doc/docs/this.md new file mode 100644 index 0000000000..ddf3a87dd0 --- /dev/null +++ b/doc/dev_doc/docs/this.md @@ -0,0 +1,35 @@ +# This documentation + +## About + +This documentation tries to gather in an easy to navigate place for a developer (no matter his area of work, it can be frontend, backend, devops, etc...) the documentation related to the development of the opensource Puter project. + +Documentation runs on mkdocs tool, an easy and powerful documentation tool written in Python. It was decided to use this tool since most of the existing documentation was in markdown format, and seeing that new contributors were also adding new documentation in markdown format. + +## Get started with docs + +1. Clone puter's repo. +2. Install mkdocs and mkdocs-material. +``` +pip install mkdocs && pip install mkdocs-material +``` +3. Navigate to the doc/dev_doc/docs directory. +4. Build the documentation +``` +mkdocs build && mkdocs serve +``` +5. Now you should have it live on the IP http://127.0.0.1:8000 + +In the ```doc/dev_doc``` directory you will find all the source files of the documentation in markdown format. You can edit them and create new ones under that directory, and incorporate them into the documentation either using the navbar of the documentation (see the doc/dev_doc/mkdocs.yml file) or using internal links with markdown. + +--- + +Using mkdocs you can install themes. For this documentation, you will need to install material theme: + +``` +pip install mkdocs-material +``` + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/mkdocs.yml b/doc/dev_doc/mkdocs.yml new file mode 100644 index 0000000000..7e1fcfb8f5 --- /dev/null +++ b/doc/dev_doc/mkdocs.yml @@ -0,0 +1,22 @@ +site_name: Puter v2.5.1 documentation + +theme: + name: material + palette: + primary: indigo + accent: pink + toggle: + icon: material/weather-sunny + name: Switch to dark mode + scheme: default + +nav: + - Home: index.md + - General System Architecture: arch.md + - Glosary: glosary.md + - Contribution Guidelines: oscon.md + - Technological Stack: stack.md + - Support: support.md + - Colaborate with this doc: this.md + - What next: roadmap.md + - Guides: dev_guides/dev_guides.md From 9fc4910bafb8d3366266be85d820ed91bf694a40 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 16:40:51 -0300 Subject: [PATCH 02/11] doc: create README for contributors docs --- doc/contributors/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 doc/contributors/README.md diff --git a/doc/contributors/README.md b/doc/contributors/README.md new file mode 100644 index 0000000000..bc618f1691 --- /dev/null +++ b/doc/contributors/README.md @@ -0,0 +1,30 @@ +# Contributors-oriented documentation + +## Where to Start + +Start with [Repo Structure and Tooling](./contributors/structure.md). + +### Index + +- **Conventions** + - [Repo Structure and Tooling](./structure.md) + - How directories and files are organized in our GitHub repo + - What tools are used to build parts of Puter + - [Comment Prefixes](./comment_prefixes.md) + - A convention we use for line comments in code + +- [Frontend Documentation](../../src/gui/doc/) +- [Backend Documentation](../../src/backend/doc/README.md) +- [Extensions](./extensions/README.md) + +## How to find documentation on something + +You will be able to find existing documentation on a contribution topic **following the structure** of the contributor documentation. +[`This is the structure`](./structure.md) of puter's contributors-oriented docs. + +## How to understand the code and work of others more easily + +**Comments** are used in code to make them easier to read. + +Also, comments uses prefixes for improve their clearness. +[`Here you will find the standard`](./comment_prefixes.md) that is followed. From 367a1ed9164c9cd031eb38dd63307e6cbb5a4cd1 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 17:40:29 -0300 Subject: [PATCH 03/11] doc(general): remove dev_docs dir doc(backend): move testing tools to backend contrib dir remove testing tools doc --- doc/dev_doc/docs/arch.md | 153 ------ .../docs/deployment/backend_boot_sequence.md | 97 ---- .../docs/deployment/first-run-issues.md | 57 --- doc/dev_doc/docs/deployment/self_host.md | 131 ----- doc/dev_doc/docs/dev_guides/dev_guides.md | 7 - .../docs/dev_guides/making_a_driver.md | 476 ------------------ doc/dev_doc/docs/glosary.md | 28 -- doc/dev_doc/docs/index.md | 166 ------ doc/dev_doc/docs/oscon.md | 127 ----- doc/dev_doc/docs/roadmap.md | 8 - doc/dev_doc/docs/stack.md | 95 ---- doc/dev_doc/docs/support.md | 17 - doc/dev_doc/docs/testing/backend_tools.md | 42 -- doc/dev_doc/docs/this.md | 35 -- doc/dev_doc/mkdocs.yml | 22 - 15 files changed, 1461 deletions(-) delete mode 100644 doc/dev_doc/docs/arch.md delete mode 100644 doc/dev_doc/docs/deployment/backend_boot_sequence.md delete mode 100644 doc/dev_doc/docs/deployment/first-run-issues.md delete mode 100644 doc/dev_doc/docs/deployment/self_host.md delete mode 100644 doc/dev_doc/docs/dev_guides/dev_guides.md delete mode 100644 doc/dev_doc/docs/dev_guides/making_a_driver.md delete mode 100644 doc/dev_doc/docs/glosary.md delete mode 100644 doc/dev_doc/docs/index.md delete mode 100644 doc/dev_doc/docs/oscon.md delete mode 100644 doc/dev_doc/docs/roadmap.md delete mode 100644 doc/dev_doc/docs/stack.md delete mode 100644 doc/dev_doc/docs/support.md delete mode 100644 doc/dev_doc/docs/testing/backend_tools.md delete mode 100644 doc/dev_doc/docs/this.md delete mode 100644 doc/dev_doc/mkdocs.yml diff --git a/doc/dev_doc/docs/arch.md b/doc/dev_doc/docs/arch.md deleted file mode 100644 index 57daa64e3a..0000000000 --- a/doc/dev_doc/docs/arch.md +++ /dev/null @@ -1,153 +0,0 @@ -# System Architecture - -## General - -Puter's system goals is to provide an internet operating system, providing (as brief): - -1. **User management:** (User) Account and session CrUD, Permissions... -2. **Desktop environment use:** (User) Use apps in interactive mode through GUIs, CrUD symbolic links and icons... -3. **System deployment:** (Developers) build a web app, or web service, on puter. - -and ensuring: - - 1. **Extensibility:** you should be able to create your own Kernel Modules, user-oriented applications, and so. - 2. **Debuggability:** given this is opensource-driven, you'll find loggers and monitoring tools aiming to make development easier. - 3. **Deployability:** you, and other users, should be able to deploy this system at least both self host and public hosting. - 4. **Securability:** you, and other users, should be able to trust on puter as a personal cloud, a remote desktop for servers and workstations, and as a software development platform. - -In order to achieve those requirements, Puter is following (tl;dr): - -1. **A client-server style Architecture:** Allow user to interact with system GUI through a Web Browser (as an external system). -2. **Micro-kernel pattern:** Allow backend (in which heavy processing occurs) to extend system's functionality, keeping the core of the system and the other additions decoupled each other. - -In in a nutshell: -``` - Puter is Puter, whatever you think it might be useful for - you can use it for. You can think of it as a high-level - operating system where the "hardware" is external services or - resources provided by the host OS; if you develop apps on - this platform you have higher-level primitives, like how - using AI services is considered a "driver", or how Puter's - filesystem can use a database to store the directory tree and - file metadata. -``` - -## Deployment - -### Local dev - -Get the [monorepo](https://github.com/HeyPuter/puter/), and then run `install` and `start` [npm scripts](https://github.com/HeyPuter/puter/blob/main/package.json) - -``` -git clone https://github.com/HeyPuter/puter -cd puter -npm install -npm start -``` - -You get in error? then you can [check our first run issues checklist.](./deployment/first-run-issues.md) - -Also, if you get "Cannot write to path" error, it usually happens when /var/puter isn\'t chown\'d to the right UID. You can check the [issue number 645.](https://github.com/HeyPuter/puter/issues/645) -### Docker - -On linux/macOS run: - -``` -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 -``` - -On Windows run: - -``` -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 -``` - -## Main modules traits - -### service - -- **Concern:** to extend core functionality. -- **Class:** BaseService (extends concepts.Service) -- **Public interface:** - -``` -/** -* Creates the service's data structures and initial values. -* This method sets up logging and error handling, and calls a custom `_construct` method if defined. -* -* @returns {Promise} A promise that resolves when construction is complete. -*/ -async construct () => void -``` - -``` -/** -* Constructs service class using Service Resources list -* Service Resources properties: services, config, my_config, name, args, context. -*/ -constructor (service_resources, ...a) -``` - - -``` -/** -* Performs service lifecycle's initialization phase -*/ -async init () => void -``` - -### Kernel - - -- **Concern:** To orchestrate core modules for system to load up, following [**Backend Boot Sequence**.](./deployment/backend_boot_sequence.md) -- **Class:** Kernel (extends AdvancedBase) -- **Public interface:** - -``` -/** -* Construct kernel module configuring its useapi and entry path -*/ -constructor (entry_path) => -``` - - -``` -/** -* Adds a module into kernel's modules list -*/ -add_module (module) => void -``` - -``` -/** -* Boots backend -*/ -boot () => void -``` - -## System entry points - -### Testing -Mocha is being used for this. -There are 2 main **test directories:** -1. src/phoenix/test -> testing phoenix emulator. -2. src/backend/tools/test -> a set of tools for backend testing. [Read more about backend tools.](./testing/backend_tools.md) - -### Use cases -For **self hosting** deployment, there is a _tool_ called "run-selfhosted.js" which you can run with ```npm run start``` command. That tool is going to: - -1. Get all required _kernel modules_ from the **@heyputer/backend npm package** -2. Configure kernel's entry path as the directory path of the current file (so, the run-selfhosted tool's directory). -3. Add all required _kernel modules_ to kernel's modules list. -4. Start kernel by its ```boots()``` public method. - -**Monitoring:** The ```SelfHostedModule``` is responsible for load 3 project's module watching tools (for GUI, TERMINAL, EMULATOR, GIT, PHOENIX, and PUTER-JS) - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/deployment/backend_boot_sequence.md b/doc/dev_doc/docs/deployment/backend_boot_sequence.md deleted file mode 100644 index 91a28b6e47..0000000000 --- a/doc/dev_doc/docs/deployment/backend_boot_sequence.md +++ /dev/null @@ -1,97 +0,0 @@ -# Puter Backend Boot Sequence - -This document describes the boot sequence of Puter's backend. - -**Runtime Environment** - - Configuration directory is determined - - Runtime directory is determined - - Mod directory is determined - - Services are instantiated - -**Construction** - - Data structures are created - -**Initialization** - - Registries are populated - - Services prepare for next phase - -**Consolidation** - - Service event bus receives first event (`boot.consolidation`) - - Services perform coordinated setup behaviors - - Services prepare for next phase - -**Activation** - - Blocking listeners of `boot.consolidation` have resolved - - HTTP servers start listening - -**Ready** - - Services are informed that Puter is providing service - -## Boot Phases - -### Construction - -Services implement a method called `construct` which initializes members -of an instance. Services do not override the class constructor of -**BaseService**. This makes it possible to use the `new` operator without -invoking a service's constructor behavior during debugging. - -The first phase of the boot sequence, "construction", is simply a loop to -call `construct` on all registered services. - -The `_construct` override should not: -- call other services -- emit events - -### Initialization - -At initialization, the `init()` method is called on all services. -The `_init` override can be used to: -- register information with other services, when services don't - need to register this information in a specific sequence. - An example of this is registering commands with CommandService. -- perform setup that is required before the consolidation phase starts. - -### Consolidation - -Consolidation is a phase where services should emit events that -are related to bringing up the system. For example, WebServerService -('web-server') emits an event telling services to install middlewares, -and later emits an event telling services to install routes. - -Consolidation starts when Kernel emits `boot.consolidation` to the -services event bus, which happens after `init()` resolves for all -services. - -### Activation - -Activation is a phase where services begin listening on external -interfaces. For example, this is when the web server starts listening. - -Activation starts when Kernel emits `boot.activation`. - -### Ready - -Ready is a phase where services are informed that everything is up. - -Ready starts when Kernel emits `boot.ready`. - -## Events and Asynchronous Execution - -The services event bus is implemented so you can `await` a call to `.emit()`. -Event listeners can choose to have blocking behavior by returning a promise. - -During emission of a particular event, listeners of this event will not -block each other, but all listeners must resolve before the call to -`.emit()` is resolved. (i.e. `emit` uses `Promise.all`) - -## Legacy Services - -Some services were implemented before the `BaseService` class - which -implements the `init` method - was created. These services are called -"legacy services" and they are instantiated _after_ initialization but -_before_ consolidation. - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/deployment/first-run-issues.md b/doc/dev_doc/docs/deployment/first-run-issues.md deleted file mode 100644 index dc12e6adcd..0000000000 --- a/doc/dev_doc/docs/deployment/first-run-issues.md +++ /dev/null @@ -1,57 +0,0 @@ -# First Run Issues - -## "Cannot find package '@heyputer/backend'" - -Scenario: You see the following output: - -``` -┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ -┃ Cannot find package '@heyputer/backend' ┃ -┃ 📝 this usually happens if you forget `npm install` ┃ -┃ Suggestions: ┃ -┃ - try running `npm install` ┃ -┃ Technical Notes: ┃ -┃ - @heyputer/backend is in an npm workspace ┃ -┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ -``` - -1. Ensure you have run `npm install`. -2. [Install build essentials for your distro](#installing-build-essentials), - then run `npm install` again. - -## Installing Build Essentials - -### Debian-based distros - -``` -sudo apt update -sudo apt install build-essential -``` - -### RHEL-family distros (Fedora, Rocky, etc) - -``` -sudo dnf groupinstall "Development Tools" -``` - -### "I use Arch btw" - -``` -sudo pacman -S base-devel -``` - -### Alpine - -If you're running in Puter's Alpine image then this is already installed. - -``` -sudo apk add build-base -``` - -### Gentoo - -You know what you're doing; you just wanted to see if we mentioned Gentoo. - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/deployment/self_host.md b/doc/dev_doc/docs/deployment/self_host.md deleted file mode 100644 index f7b1201b0e..0000000000 --- a/doc/dev_doc/docs/deployment/self_host.md +++ /dev/null @@ -1,131 +0,0 @@ -# Self-Hosting Puter - -> [!WARNING] -> The self-hosted version of Puter is currently in alpha stage and should not be used in production yet. It is under active development and may contain bugs, other issues. Please exercise caution and use it for testing and evaluation purposes only. - -### Self-Hosting Differences -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 access apps from puter.com (see below) -- Several "core" apps are missing, such as **Code** or **Draw** -- Some assets are different - -Work is ongoing to improve the **App Center** and make it available on self-hosted. -Until then, it is still possible to add apps using the **Dev Center** app. - -
- -## Configuration - -Running the server will generate a configuration file in one of these locations: -- `config/config.json` when [Using Docker](#using-docker) -- `volatile/config/config.json` in [Local Development](#local-development) -- `/etc/puter/config.json` on a server (or within a Docker container) - -### Domain Name - -To access Puter on your device, you can simply go to the address printed in -the server console (usually `puter.localhost:4100`). - -To access Puter from another device, a domain name must be configured, as well as -an `api` subdomain. For example, `example.local` might be the domain name pointing -to the IP address of the server running puter, and `api.example.com` must point to -this address as well. This domain must be specified in the configuration file -(usually `volatile/config/config.json`) as well. - -See [domain configuration](#configuring-domains-for-self-hosted-puter) for more information. - -### Configure the Port - -- You can specify a custom port by setting `http_port` to a desired value -- If you're using a reverse-proxy such as nginx or cloudflare, you should - also set `pub_port` to the public (external) port (usually `443`) -- If you have HTTPS enabled on your reverse-proxy, ensure that - `protocol` in config.json is set accordingly - -### Default User - -By default, Puter will create a user called `default_user`. -This user will have a randomly generated password, which will be printed -in the development console. -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 -your first step. - -
- -## Configuring Domains for Self-Hosted Puter - -### Local Network Configuration - -#### Prerequisite Conditions - -Ensure the hosting device has a static IP address to prevent potential connectivity issues due to IP changes. This setup will enable seamless access to Puter and its services across your local network. - -#### Using Hosts Files - -The hosts file is a straightforward way to map domain names to IP addresses on individual devices. It's simple to set up but requires manual changes on each device that needs access to the domains. - -##### Windows -1. Open Notepad as an administrator. -2. Open the file located at `C:\Windows\System32\drivers\etc\hosts`. -3. Add lines for your domain and subdomain with the server's IP address, in the - following format: - ``` - 192.168.1.10 puter.local - 192.168.1.10 api.puter.local - ``` - -##### For macOS and Linux: -1. Open a terminal. -2. Edit the hosts file with a text editor, e.g., `sudo nano /etc/hosts`. -3. Add lines for your domain and subdomain with the server's IP address, in the - following format: - ``` - 192.168.1.10 puter.local - 192.168.1.10 api.puter.local - ``` -4. Save and exit the editor. - - -#### Using Router Configuration - -Some routers allow you to add custom DNS rules, letting you configure domain names network-wide without touching each device. - -1. Access your router’s admin interface (usually through a web browser). -2. Look for DNS or DHCP settings. -3. Add custom DNS mappings for `puter.local` and `api.puter.local` to the hosting device's IP address. -4. Save the changes and reboot the router if necessary. - -This method's availability and steps may vary depending on your router's model and firmware. - -#### Using Local DNS - -Setting up a local DNS server on your network allows for flexible and scalable domain name resolution. This method works across all devices automatically once they're configured to use the DNS server. - -##### Options for DNS Software: - -- **Pi-hole**: Acts as both an ad-blocker and a DNS server. Ideal for easy setup and maintenance. -- **BIND9**: Offers comprehensive DNS server capabilities for complex setups. -- **dnsmasq**: Lightweight and suitable for smaller networks or those new to running a DNS server. - -**contributors note:** feel free to add any software you're aware of -which might help with this to the list. Also, feel free to add instructions here for specific software; our goal is for Puter to be easy to setup with tools you're already familiar with. - -##### General Steps: - -1. Choose and install DNS server software on a device within your network. -2. Configure the DNS server to resolve `puter.local` and `api.puter.local` to the IP address of your Puter hosting device. -3. Update your router's DHCP settings to distribute the DNS server's IP address to all devices on the network. - -By setting up a local DNS server, you gain the most flexibility and control over your network's domain name resolution, ensuring that all devices can access Puter and its API without manual configuration. - -### Production Configuration - -Please note the self-hosting feature is still in alpha and a public production -deployment is not recommended at this time. However, if you wish to host -publicly you can do so following the same steps you normally would to configure -a domain name and ensuring the `api` subdomain points to the server as well. - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/dev_guides/dev_guides.md b/doc/dev_doc/docs/dev_guides/dev_guides.md deleted file mode 100644 index 6d3e9d827a..0000000000 --- a/doc/dev_doc/docs/dev_guides/dev_guides.md +++ /dev/null @@ -1,7 +0,0 @@ -# Dev guides - -This is a collection of development guides that follow the practices, tools and conventions of the project. - -1. [How to make a driver.](./making_a_driver.md) -> There is also a [video from Eric on this](https://www.youtube.com/watch?v=8znQmrKgNxA) -2. [Passing argumentos to phoenix shell](https://www.youtube.com/watch?v=VDPu7hwBsq8) diff --git a/doc/dev_doc/docs/dev_guides/making_a_driver.md b/doc/dev_doc/docs/dev_guides/making_a_driver.md deleted file mode 100644 index 47d77aeb45..0000000000 --- a/doc/dev_doc/docs/dev_guides/making_a_driver.md +++ /dev/null @@ -1,476 +0,0 @@ -# How to Make a Puter Driver - -## What is a Driver? - -A driver can be one of two things depending on what you're -talking about: -- a **driver interface** describes a general type of service - and what its parameters and result look like. - For example, `puter-chat-completion` is a driver interface - for AI Chat services, and it specifies that any service - on Puter for AI Chat needs a method called `complete` that - accepts a JSON parameter called `messages`. -- a **driver implementation** exists when a **Service** on - Puter implements a **trait** with the same name as a - driver interface. - -## Part 1: Choose or Create a Driver Interface - -Available driver interfaces exist at this location in the repo: -[/src/backend/src/services/drivers/interfaces.js](../src/services/drivers/interfaces.js). - -When creating a new Puter driver implementation, you should check -this file to see if there's an appropriate interface. We're going -to make a driver that returns greeting strings, so we can use the -existing `hello-world` interface. If there wasn't an existing -interface, it would need to be created. Let's break down this -interface: - -```javascript -'hello-world': { - description: 'A simple driver that returns a greeting.', - methods: { - greet: { - description: 'Returns a greeting.', - parameters: { - subject: { - type: 'string', - optional: true, - }, - }, - result: { type: 'string' }, - } - } -}, -``` - -The **description** describes what the interface is for. This -should be provided that both driver developers and users can -quickly identify what types of services should use it. - -The **methods** object should have at least one entry, but it -may have more. The key of each entry is the name of a method; -in here we see `greet`. Each method also has a description, -a **parameters** object, and a **result** object. - -The **parameters** object has an entry for each parameter that -may be passed to the method. Each entry is an object with a -`type` property specifying what values are allowed, and possibly -an `optional: true` entry. - -All methods for Puter drivers use _named parameters_. There are no -positional parameters in Puter driver methods. - -The **result** object specifies the type of the result. A service -called DriverService will use this to determine the response format -and headers of the response. - -## Part 2: Create a Service - -Creating a service is very easy, provided the service doesn't do -anything. Simply add a class to `src/backend/src/services` or into -the module of your choice (`src/backend/src/modules/`) -that looks like this: - -```javascript -const BaseService = require('./BaseService') -// NOTE: the path specified ^ HERE might be different depending -// on the location of your file. - -class PrankGreetService extends BaseService { -} -``` - -Notice I called the service "PrankGreet". This is a good service -name because you already know what the service is likely to -implement: this service generates a greeting, but it is a greeting -that intends to play a prank on whoever is beeing greeted. - -Then, register the service into a module. If you put the service -under `src/backend/src/services`, then it goes in -[CoreModule](..//src/CoreModule.js) somewhere near the end of -the `install()` method. Otherwise, it will go in the `*Module.js` -file in the module where you placed your service. - -The code to register the service is two lines of code that will -look something like this: - -```javascript -const { PrankGreetServie } = require('./path/to/PrankGreetServie.js'); -services.registerService('prank-greet', PrankGreetServie); -``` - -## Part 3: Verify that the Service is Registered - -It's always a good idea to verify that the service is loaded -when starting Puter. Otherwise, you might spend time trying to -determine why your code doesn't work, when in fact it's not -running at all to begin with. - -To do this, we'll add an `_init` handler to the service that -logs a message after a few seconds. We wait a few seconds so that -any log noise from boot won't bury our message. - -```javascript -class PrankGreetService extends BaseService { - async _init () { - // Wait for 5 seconds - await new Promise(rslv => setTimeout(rslv), 5000); - - // Display a log message - this.log.noticeme('Hello from PrankGreetService!'); - } -} -``` - -Typically you'll use `this.log.info('some message')` in your logs -as opposed to `this.log.noticeme(...)`, but the `noticeme` log -level is helpful when debugging. - -## Part 4: Implement the Driver Interface in your Service - -Now that it has been verified that the service is loaded, we can -start implementing the driver interface we chose eralier. - -```javascript -class PrankGreetService extends BaseService { - async _init () { - // ... same as before - } - - // Now we add this: - static IMPLEMENTS = { - ['hello-world']: { - async greet ({ subject }) { - if ( subject ) { - return `Hello ${subject}, tell me about updog!`; - } - return `Hello, tell me about updog!`; - } - } - } -} -``` - -## Part 5: Test the Driver Implementation - -We have now created the `prank-greet` implementation of `hello-world`. -Let's make a request in the browser to check it out. The example below -is a `fetch` call using `http://api.puter.localhost:4100` as the API -origin, which is the default when you're running Puter's backend locally. - -Also, in this request I refer to `puter.authToken`. If you run this -snippet in the Dev Tools window of your browser from a tab with Puter -open (your local Puter, to be precise), this should contain the current -value for your auth token. - -```javascript -await (await fetch("http://api.puter.localhost:4100/drivers/call", { - "headers": { - "Content-Type": "application/json", - "Authorization": `Bearer ${puter.authToken}`, - }, - "body": JSON.stringify({ - interface: 'hello-world', - service: 'prank-greet', - method: 'greet', - args: { - subject: 'World', - }, - }), - "method": "POST", -})).json(); -``` - -**You might see a permissions error!** Don't worry, this is expected; -in the next step we'll add the required permissions. - -## Part 6: Permissions - -In the previous step, you will only have gotten a successful response -if you're logged in as the `admin` user. If you're logged in as another -user you won't have access to the service's driver implementations be -default. - -To grant permission for all users, update -[hardcoded-permissions.js](../src/data/hardcoded-permissions.js). - -First, look for the constant `hardcoded_user_group_permissions`. -Whereever you see an entry for `service:hello-world:ii:hello-world`, add -the corresponding entry for your service, which will be called -``` -service:prank-greet:ii:hello-world -``` - -To help you remember the permission string, its helpful to know that -`ii` in the string stands for "invoke interface". i.e. the scope of the -permission is under `service:prank-greet` (the `prank-greet` service) -and we want permission to invoke the interface `hello-world` on that -service. - -You'll notice each entry in `hardcoded_user_group_permissions` has a value -determined by a call to the utility function `policy_perm(...)`. The policy -called `user.es` is a permissive policy for storage drivers, and we can -re-purpose it for our greeting implementor. - -The policy of a permission determines behavior like rate limiting. This is -an advanced topic that is not covered in this guide. - -If you want apps to be able to access the driver implementation without -explicit permission from a user, you will need to also register it in the -`default_implicit_user_app_permissions` constant. Additionally, you can -use the `implicit_user_app_permissions` constant to grant implicit -permission to the builtin Puter apps only. - -Permissions to implementations on services can also be granted at runtime -to a user or group of users using the permissions API. This is beyond the -scope of this guide. - -## Part 7: Verify Successful Response - -If all went well, you should see the response in your console when you -try the request from Part 5. Try logging into a user other than `admin` -to verify permisison is granted. - -```json -"Hello World, tell me about updog!" -``` How to Make a Puter Driver - -## What is a Driver? - -A driver can be one of two things depending on what you're -talking about: -- a **driver interface** describes a general type of service - and what its parameters and result look like. - For example, `puter-chat-completion` is a driver interface - for AI Chat services, and it specifies that any service - on Puter for AI Chat needs a method called `complete` that - accepts a JSON parameter called `messages`. -- a **driver implementation** exists when a **Service** on - Puter implements a **trait** with the same name as a - driver interface. - -## Part 1: Choose or Create a Driver Interface - -Available driver interfaces exist at this location in the repo: -[/src/backend/src/services/drivers/interfaces.js](../src/services/drivers/interfaces.js). - -When creating a new Puter driver implementation, you should check -this file to see if there's an appropriate interface. We're going -to make a driver that returns greeting strings, so we can use the -existing `hello-world` interface. If there wasn't an existing -interface, it would need to be created. Let's break down this -interface: - -```javascript -'hello-world': { - description: 'A simple driver that returns a greeting.', - methods: { - greet: { - description: 'Returns a greeting.', - parameters: { - subject: { - type: 'string', - optional: true, - }, - }, - result: { type: 'string' }, - } - } -}, -``` - -The **description** describes what the interface is for. This -should be provided that both driver developers and users can -quickly identify what types of services should use it. - -The **methods** object should have at least one entry, but it -may have more. The key of each entry is the name of a method; -in here we see `greet`. Each method also has a description, -a **parameters** object, and a **result** object. - -The **parameters** object has an entry for each parameter that -may be passed to the method. Each entry is an object with a -`type` property specifying what values are allowed, and possibly -an `optional: true` entry. - -All methods for Puter drivers use _named parameters_. There are no -positional parameters in Puter driver methods. - -The **result** object specifies the type of the result. A service -called DriverService will use this to determine the response format -and headers of the response. - -## Part 2: Create a Service - -Creating a service is very easy, provided the service doesn't do -anything. Simply add a class to `src/backend/src/services` or into -the module of your choice (`src/backend/src/modules/`) -that looks like this: - -```javascript -const BaseService = require('./BaseService') -// NOTE: the path specified ^ HERE might be different depending -// on the location of your file. - -class PrankGreetService extends BaseService { -} -``` - -Notice I called the service "PrankGreet". This is a good service -name because you already know what the service is likely to -implement: this service generates a greeting, but it is a greeting -that intends to play a prank on whoever is beeing greeted. - -Then, register the service into a module. If you put the service -under `src/backend/src/services`, then it goes in -[CoreModule](..//src/CoreModule.js) somewhere near the end of -the `install()` method. Otherwise, it will go in the `*Module.js` -file in the module where you placed your service. - -The code to register the service is two lines of code that will -look something like this: - -```javascript -const { PrankGreetServie } = require('./path/to/PrankGreetServie.js'); -services.registerService('prank-greet', PrankGreetServie); -``` - -## Part 3: Verify that the Service is Registered - -It's always a good idea to verify that the service is loaded -when starting Puter. Otherwise, you might spend time trying to -determine why your code doesn't work, when in fact it's not -running at all to begin with. - -To do this, we'll add an `_init` handler to the service that -logs a message after a few seconds. We wait a few seconds so that -any log noise from boot won't bury our message. - -```javascript -class PrankGreetService extends BaseService { - async _init () { - // Wait for 5 seconds - await new Promise(rslv => setTimeout(rslv), 5000); - - // Display a log message - this.log.noticeme('Hello from PrankGreetService!'); - } -} -``` - -Typically you'll use `this.log.info('some message')` in your logs -as opposed to `this.log.noticeme(...)`, but the `noticeme` log -level is helpful when debugging. - -## Part 4: Implement the Driver Interface in your Service - -Now that it has been verified that the service is loaded, we can -start implementing the driver interface we chose eralier. - -```javascript -class PrankGreetService extends BaseService { - async _init () { - // ... same as before - } - - // Now we add this: - static IMPLEMENTS = { - ['hello-world']: { - async greet ({ subject }) { - if ( subject ) { - return `Hello ${subject}, tell me about updog!`; - } - return `Hello, tell me about updog!`; - } - } - } -} -``` - -## Part 5: Test the Driver Implementation - -We have now created the `prank-greet` implementation of `hello-world`. -Let's make a request in the browser to check it out. The example below -is a `fetch` call using `http://api.puter.localhost:4100` as the API -origin, which is the default when you're running Puter's backend locally. - -Also, in this request I refer to `puter.authToken`. If you run this -snippet in the Dev Tools window of your browser from a tab with Puter -open (your local Puter, to be precise), this should contain the current -value for your auth token. - -```javascript -await (await fetch("http://api.puter.localhost:4100/drivers/call", { - "headers": { - "Content-Type": "application/json", - "Authorization": `Bearer ${puter.authToken}`, - }, - "body": JSON.stringify({ - interface: 'hello-world', - service: 'prank-greet', - method: 'greet', - args: { - subject: 'World', - }, - }), - "method": "POST", -})).json(); -``` - -**You might see a permissions error!** Don't worry, this is expected; -in the next step we'll add the required permissions. - -## Part 6: Permissions - -In the previous step, you will only have gotten a successful response -if you're logged in as the `admin` user. If you're logged in as another -user you won't have access to the service's driver implementations be -default. - -To grant permission for all users, update -[hardcoded-permissions.js](../src/data/hardcoded-permissions.js). - -First, look for the constant `hardcoded_user_group_permissions`. -Whereever you see an entry for `service:hello-world:ii:hello-world`, add -the corresponding entry for your service, which will be called -``` -service:prank-greet:ii:hello-world -``` - -To help you remember the permission string, its helpful to know that -`ii` in the string stands for "invoke interface". i.e. the scope of the -permission is under `service:prank-greet` (the `prank-greet` service) -and we want permission to invoke the interface `hello-world` on that -service. - -You'll notice each entry in `hardcoded_user_group_permissions` has a value -determined by a call to the utility function `policy_perm(...)`. The policy -called `user.es` is a permissive policy for storage drivers, and we can -re-purpose it for our greeting implementor. - -The policy of a permission determines behavior like rate limiting. This is -an advanced topic that is not covered in this guide. - -If you want apps to be able to access the driver implementation without -explicit permission from a user, you will need to also register it in the -`default_implicit_user_app_permissions` constant. Additionally, you can -use the `implicit_user_app_permissions` constant to grant implicit -permission to the builtin Puter apps only. - -Permissions to implementations on services can also be granted at runtime -to a user or group of users using the permissions API. This is beyond the -scope of this guide. - -## Part 7: Verify Successful Response - -If all went well, you should see the response in your console when you -try the request from Part 5. Try logging into a user other than `admin` -to verify permisison is granted. - -```json -"Hello World, tell me about updog!" - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/glosary.md b/doc/dev_doc/docs/glosary.md deleted file mode 100644 index 89fbf2cd50..0000000000 --- a/doc/dev_doc/docs/glosary.md +++ /dev/null @@ -1,28 +0,0 @@ -# Puter's glosary - -## General - -1. **Puter:** Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. - -2. **Self hosting:** Means running and managing the app on your infrastructure instead of using thid-party hosting service. -You can learn more on how to self host your Puter instance [here](./deployment/self_host.md) - -3. **Kernel:** It is a simple module which is in charge of orchestrating the initialization of the system, following the boot sequence. Following the [Microkernel pattern](https://www.oreilly.com/library/view/software-architecture-patterns/9781098134280/ch04.html), this module corresponds to the Core of Puter backend. - -4. **Monorepo:** A centralised source code repository made of several interrelated packages. - -5. **npm workspace:** An NPM workspace is a NPM feature that allows you to **manage multiple related packages** (like a monorepo) within a single repository. - -## Backend components - -1. **BasicBase:** Abstract class with inheritance tracking for composite the system using shared configuration and behaviors. -2. **FeatureBase:** Extending BasicBase, allows defining and install features (classes and modules) as TopicsFeature, MariMethodsfeature, and others. -3. **AdvancedBase:** Extending FeatureBase, Defines features to be installed by Its FeatureBase parent instance. - -> As you can see, components follows an inheritance chain which starts in BasicBase. - -4. **KernelModule:** Extending AdvancedBase, orchestrate system boot sequence. - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/index.md b/doc/dev_doc/docs/index.md deleted file mode 100644 index be97eb1a78..0000000000 --- a/doc/dev_doc/docs/index.md +++ /dev/null @@ -1,166 +0,0 @@ -

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

- -

The Internet OS! Free, Open-Source, and Self-Hostable.

- -

- « LIVE DEMO » -
-
- Puter.com - · - SDK - · - CLI - · - Discord - · - Reddit - · - X -

- -

screenshot

- -
- -## Puter - -Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. Puter can be used as: - -- A privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time. -- A platform for building and publishing websites, web apps, and games. -- An alternative to Dropbox, Google Drive, OneDrive, etc. with a fresh interface and powerful features. -- A remote desktop environment for servers and workstations. -- A friendly, open-source project and community to learn about web development, cloud computing, distributed systems, and much more! - -
- -## Getting Started - -### 💻 Local Development - -```bash -git clone https://github.com/HeyPuter/puter -cd puter -npm install -npm start -``` - -This will launch Puter at http://puter.localhost:4100 (or the next available port). - -If this does not work, see [First Run Issues](./doc/first-run-issues.md) for -troubleshooting steps. - -
- -### 🐳 Docker - -```bash -mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter -``` - -
- -### 🐙 Docker Compose - -#### Linux/macOS - -```bash -mkdir -p puter/config puter/data -sudo chown -R 1000:1000 puter -wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml -docker compose up -``` - -
- -#### Windows - -```powershell -mkdir -p puter -cd puter -New-Item -Path "puter\config" -ItemType Directory -Force -New-Item -Path "puter\data" -ItemType Directory -Force -Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" -docker compose up -``` - -
- -### 🚀 Self-Hosting - -For detailed guides on self-hosting Puter, including configuration options and best practices, see our [Self-Hosting Documentation](https://github.com/HeyPuter/puter/blob/main/doc/self-hosters/instructions.md). - -
- -### ☁️ Puter.com - -Puter is available as a hosted service at [**puter.com**](https://puter.com). - -
- -## System Requirements - -- **Operating Systems:** Linux, macOS, Windows -- **RAM:** 2GB minimum (4GB recommended) -- **Disk Space:** 1GB free space -- **Node.js:** Version 16+ (Version 22+ recommended) -- **npm:** Latest stable version - -
- -## Support - -Connect with the maintainers and community through these channels: - -- Bug report or feature request? Please [open an 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) -- Security issues? [security@puter.com](mailto:security@puter.com) -- Email maintainers at [hi@puter.com](mailto:hi@puter.com) - -We are always happy to help you with any questions you may have. Don't hesitate to ask! - -
- -## License - -This repository, including all its contents, sub-projects, modules, and components, is licensed under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses. - -
- -## Translations - -- [Arabic / العربية](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ar.md) -- [Armenian / Հայերեն](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hy.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) -- [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) -- [English](https://github.com/HeyPuter/puter/blob/main/README.md) -- [Farsi / فارسی](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fa.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) -- [German/ Deutsch](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.de.md) -- [Hebrew/ עברית](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.he.md) -- [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) -- [Hungarian / Magyar](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hu.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) -- [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) -- [Malayalam / മലയാളം](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ml.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) -- [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) -- [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) -- [Swedish / Svenska](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.sv.md) -- [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) -- [Telugu / తెలుగు](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.te.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) -- [Ukrainian / Українська](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ua.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) diff --git a/doc/dev_doc/docs/oscon.md b/doc/dev_doc/docs/oscon.md deleted file mode 100644 index 477566a97d..0000000000 --- a/doc/dev_doc/docs/oscon.md +++ /dev/null @@ -1,127 +0,0 @@ -# Contributing to Puter - -Welcome to Puter, the open-source distributed internet operating system. We're excited to have you contribute to our project, whether you're reporting bugs, suggesting new features, or contributing code. This guide will help you get started with contributing to Puter in different ways. - -
- -# Report bugs - -Before reporting a bug, please check our [the issues on our GitHub repository](https://github.com/HeyPuter/puter/issues) to see if the bug has already been reported. If it has, you can add a comment to the existing issue with any additional information you have. - -If you find a new bug in Puter, please [open an issue on our GitHub repository](https://github.com/HeyPuter/puter/issues/new). We'll do our best to address the issue as soon as possible. When reporting a bug, please include as much information as possible, including: - -- A clear and descriptive title -- A description of the issue -- Steps to reproduce the bug -- Expected behavior -- Actual behavior -- Screenshots, if applicable -- Your host operating system and browser -- Your Puter version, location, ... - -Please open a separate issue for each bug you find. - -Maintainers will apply the appropriate labels to your issue. - -
- -# Suggest new features - -If you have an idea for a new feature in Puter, please open a new discussion thread on our [GitHub repository](https://github.com/HeyPuter/puter/discussions) to discuss your idea with the community. We'll do our best to respond to your suggestion as soon as possible. - -When suggesting a new feature, please include as much information as possible, including: - -- A clear and descriptive title -- A description of the feature -- The problem the feature will solve -- Any relevant screenshots or mockups -- Any relevant links or resources - -
- -# Contribute code - -If you'd like to contribute code to Puter, you need to fork the project and submit a pull request. If this is your first time contributing to an open-source project, we recommend reading this short guide by GitHub on [how to contribute to a project](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project). - -We'll review your pull request and work with you to get your changes merged into the project. - -## Repository Structure - -![file structure](./doc/File%20Structure.drawio.png) - -## Your first code contribution - -We maintain a list of issues that are good for first-time contributors. You can find these issues by searching for the [`good first issue`](https://github.com/HeyPuter/puter/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label in our [GitHub repository](https://github.com/HeyPuter/puter). These issues are designed to be relatively easy to fix, and we're happy to help you get started. Pick an issue that interests you, and leave a comment on the issue to let us know you're working on it. - -## Documentation for Contributors - -### Backend -See [src/backend/CONTRIBUTING.md](src/backend/CONTRIBUTING.md) - -
- -## 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) - -
- -## Commit Messages - -**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. - -### Conventional Commits -We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) with the following prefixes: -- `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: -- If the commit message is in _past tense_, it's a shorthand for the following: - - `dev: apply changes that would be applied after one had ` -- If the commit message is in _present tense_, it's shorthand for the following: - - `dev: apply changes that would be applied after ` - -For example, the following are correct: -- `dev: improved readdir` - - interpret this as: `dev: apply changes that would be applied after one had improved readdir` -- `dev: improving readdir` - - interpret this as: `dev: apply changes that would be applied after improving readdir` - -
- -## Code Review - -Once you've submitted your pull request, the project maintainers will review your changes. We may suggest some changes or improvements. This is a normal part of the process, and your contributions are greatly appreciated! - -
- -## Contribution License Agreement (CLA) - -Like many open source projects, we require contributors to sign a Contribution License Agreement (CLA) before we can accept your code. When you open a pull request for the first time, a bot will automatically add a comment with a link to the CLA. You can sign the CLA electronically by following the link and filling out the form. - -
- -# Getting Help - -If you have any questions about Puter, please feel free to reach out to us through the following channels: - -- [Discord](https://discord.com/invite/PQcx7Teh8u) -- [Reddit](https://www.reddit.com/r/Puter/) -- [Twitter](https://twitter.com/HeyPuter) -- [Email](mailto:support@puter.com) - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/roadmap.md b/doc/dev_doc/docs/roadmap.md deleted file mode 100644 index 05e60bd8f1..0000000000 --- a/doc/dev_doc/docs/roadmap.md +++ /dev/null @@ -1,8 +0,0 @@ -# What next? - -This is a project under development with current working releases [check our changelog.](https://github.com/HeyPuter/puter/releases/) -This documentation is under development too, and you could improve it with your pr. - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/stack.md b/doc/dev_doc/docs/stack.md deleted file mode 100644 index a2dabb1997..0000000000 --- a/doc/dev_doc/docs/stack.md +++ /dev/null @@ -1,95 +0,0 @@ -# Stack of puter - -Puter source is modular, meaning that there are a **node module for each src/ folder subdirectory**. -That means each module could be defining its own package dependency list. - -## General - -1. Using Javascript as main language. -2. Using DHTML (html,js,css) for dinamic web rendering. -3. Using Shell and Docker for building and deployment scripts. -4. Using Docker for containerized deployment. -5. Using SQLITE for persistence (of sessions, app storage...) -6. Using local disk for some storage operations. - -## Node related - -Puter currently Node-related stack is: - -### DevDependencies - -1. **[@eslint/js](https://eslint.org/docs/latest/)** - Official ESLint extension to handle JavaScript specific rules. - -2. **[chalk](https://github.com/chalk/chalk)** - Allows formating terminal output with colors and styles. - -3. **[clean-css](https://github.com/clean-css/clean-css)** - Efficient CSS minifier. - -4. **[dotenv](https://github.com/motdotla/dotenv#readme)** - Load environment variables from a `.env` file into `process.env`. - -5. **[eslint](https://eslint.org/docs/latest/)** - Static analysis tool to find and fix problems in JavaScript code. - -6. **[express](https://expressjs.com/)** - Minimalistic framework for building web applications in Node.js. - -7. **[globals](https://github.com/sindresorhus/globals#readme)** - List of global variables recognized in different environments. - -8. **[html-entities](https://github.com/mdevils/html-entities#readme)** - Encodes and decodes HTML entities in JavaScript. - -9. **[html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin#readme)** - Automatically generates HTML files for Webpack projects. - -10. **[license-check-and-add](https://github.com/mjhenkes/license-check-and-add#readme)** - Automatically checks and adds licenses to project files. - -11. **[mocha](https://mochajs.org/)** - JavaScript testing framework with support for asynchronous testing. - -12. **[nodemon](https://github.com/remy/nodemon#readme)** - Automatically reloads a Node.js application when it detects code changes. - -13. **[uglify-js](https://github.com/mishoo/UglifyJS#readme)** - Minifies and optimizes JavaScript code to reduce its size. - -14. **[webpack](https://webpack.js.org/)** - Module packer for JavaScript. - -### Dependencies - -16. **[javascript-time-ago](https://github.com/catamphetamine/javascript-time-ago#readme)** - Friendly formatting of dates and times in different languages. - -17. **[json-colorizer](https://github.com/kaelzhang/node-json-colorizer#readme)** - Format and colorize JSON output in the terminal. - -18. **[open](https://github.com/sindresorhus/open#readme)** - Opens default URLs, files or applications from Node.js. - -19. **[sharp](https://sharp.pixelplumbing.com/)** - Fast and optimized image processing library for Node.js. - -20. **[sharp-bmp](https://github.com/karaggeorge/sharp-bmp#readme)** - Sharp extension to handle BMP images. - -21. **[sharp-ico](https://github.com/karaggeorge/sharp-ico#readme)** - Sharp extension to handle ICO images. - -22. **[simple-git](https://github.com/steveukx/git-js#readme)** - Simple interface to work with Git in Node.js. - -23. **[string-template](https://github.com/Matt-Esch/string-template#readme)** - Simple string-based template engine. - -24. **[uuid](https://github.com/uuidjs/uuid#readme)** - Unique generator of UUID identifiers according to RFC standards. - - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/support.md b/doc/dev_doc/docs/support.md deleted file mode 100644 index 3f5d2ac4ad..0000000000 --- a/doc/dev_doc/docs/support.md +++ /dev/null @@ -1,17 +0,0 @@ -# Support - -Connect with the maintainers and community through these official channels: - -- Bug report or feature request? Please [open an 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) -- Security issues? [security@puter.com](mailto:security@puter.com) -- Email maintainers at [hi@puter.com](mailto:hi@puter.com) - -We are always happy to help you with any questions you may have. Don't hesitate to ask! - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/testing/backend_tools.md b/doc/dev_doc/docs/testing/backend_tools.md deleted file mode 100644 index ffefc80834..0000000000 --- a/doc/dev_doc/docs/testing/backend_tools.md +++ /dev/null @@ -1,42 +0,0 @@ -# Backend Tools Directory - -## Test Kernel - -The **Test Kernel** is a drop-in replacement for Puter's main kernel. Instead of -actually initializing and running services, it only registers them and then invokes -a test iterator through all the services. - -The Test Kernel is ideal for running unit and integration tests against individual services, ensuring they behave correctly. - -### Test Kernel Notes - -1. **Logging**: - A custom `TestLogger` is provided for simplified logging output during tests. - Since LogService is never initialized, this is never replaced. - -2. **Context Management**: - The Test Kernel uses the same `Context` system as the main Kernel. This gives test environments a consistent way to access global state, configuration, and service containers. - -3. **Assertion & Results Tracking**: - The Test Kernel includes a simple testing structure that: - - Tracks passed and failed assertions. - - Repeats assertion outputs at the end of test runs for clarity. - - Allows specifying which services to test via command-line arguments. - -### Typical Workflow - -1. **Initialization**: - Instantiate the Test Kernel, and add any modules you want to test. - -2. **Module Installation**: - The Test Kernel installs these modules (via `_install_modules()`), making their services available in the `Container`. - -3. **Service Testing**: - After modules are installed, each service can be constructed and tested. Tests are implemented as `_test()` methods on services, using simple assertion helpers (`testapi.assert` and `testapi.assert.equal`). - -4. **Result Summarization**: - Once all tests run, the Test Kernel prints a summary of passed and failed assertions, aiding quick evaluation of test outcomes. - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/docs/this.md b/doc/dev_doc/docs/this.md deleted file mode 100644 index ddf3a87dd0..0000000000 --- a/doc/dev_doc/docs/this.md +++ /dev/null @@ -1,35 +0,0 @@ -# This documentation - -## About - -This documentation tries to gather in an easy to navigate place for a developer (no matter his area of work, it can be frontend, backend, devops, etc...) the documentation related to the development of the opensource Puter project. - -Documentation runs on mkdocs tool, an easy and powerful documentation tool written in Python. It was decided to use this tool since most of the existing documentation was in markdown format, and seeing that new contributors were also adding new documentation in markdown format. - -## Get started with docs - -1. Clone puter's repo. -2. Install mkdocs and mkdocs-material. -``` -pip install mkdocs && pip install mkdocs-material -``` -3. Navigate to the doc/dev_doc/docs directory. -4. Build the documentation -``` -mkdocs build && mkdocs serve -``` -5. Now you should have it live on the IP http://127.0.0.1:8000 - -In the ```doc/dev_doc``` directory you will find all the source files of the documentation in markdown format. You can edit them and create new ones under that directory, and incorporate them into the documentation either using the navbar of the documentation (see the doc/dev_doc/mkdocs.yml file) or using internal links with markdown. - ---- - -Using mkdocs you can install themes. For this documentation, you will need to install material theme: - -``` -pip install mkdocs-material -``` - ---- - -If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/dev_doc/mkdocs.yml b/doc/dev_doc/mkdocs.yml deleted file mode 100644 index 7e1fcfb8f5..0000000000 --- a/doc/dev_doc/mkdocs.yml +++ /dev/null @@ -1,22 +0,0 @@ -site_name: Puter v2.5.1 documentation - -theme: - name: material - palette: - primary: indigo - accent: pink - toggle: - icon: material/weather-sunny - name: Switch to dark mode - scheme: default - -nav: - - Home: index.md - - General System Architecture: arch.md - - Glosary: glosary.md - - Contribution Guidelines: oscon.md - - Technological Stack: stack.md - - Support: support.md - - Colaborate with this doc: this.md - - What next: roadmap.md - - Guides: dev_guides/dev_guides.md From 69c185f54fc390731d690231b0b8b091eb450de9 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 16:43:35 -0300 Subject: [PATCH 04/11] docs(general): link contributors docs from main doc directory Moved the sub-Index of contents of the contributor documentation subsection into the main contributor documentation file to make it easier to make changes to the directory without breaking links in the future. --- doc/README.md | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/doc/README.md b/doc/README.md index 0179ada86e..4ae61ec66f 100644 --- a/doc/README.md +++ b/doc/README.md @@ -27,19 +27,4 @@ to ask questions. ## Contributor Documentation -### Where to Start - -Start with [Repo Structure and Tooling](./contributors/structure.md). - -### Index - -- **Conventions** - - [Repo Structure and Tooling](./contributors/structure.md) - - How directories and files are organized in our GitHub repo - - What tools are used to build parts of Puter - - [Comment Prefixes](./contributors/comment_prefixes.md) - - A convention we use for line comments in code - -- [Frontend Documentation](/src/gui/doc) -- [Backend Documentation](/src/backend/doc) -- [Extensions](./contributors/extensions/) +Interested in contributing? [Find all documentation for Puter's contributors here.](./contributors/README.md) From 61cd9e1d254dde2ebbf6f4e7b63b702dd7398272 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 17:08:23 -0300 Subject: [PATCH 05/11] doc(contrib/guides): create dev guides documentation --- doc/contributors/guides/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/contributors/guides/README.md diff --git a/doc/contributors/guides/README.md b/doc/contributors/guides/README.md new file mode 100644 index 0000000000..6d3e9d827a --- /dev/null +++ b/doc/contributors/guides/README.md @@ -0,0 +1,7 @@ +# Dev guides + +This is a collection of development guides that follow the practices, tools and conventions of the project. + +1. [How to make a driver.](./making_a_driver.md) +> There is also a [video from Eric on this](https://www.youtube.com/watch?v=8znQmrKgNxA) +2. [Passing argumentos to phoenix shell](https://www.youtube.com/watch?v=VDPu7hwBsq8) From d7abd6e38d0ee7082f56f902fdb934eddb7f97c6 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 17:09:51 -0300 Subject: [PATCH 06/11] doc(contrib/guides): move doc on making a driver --- doc/contributors/guides/README.md | 4 +- doc/contributors/guides/how_to_make_driver.md | 476 ++++++++++++++++++ src/backend/doc/howto_make_driver.md | 237 --------- 3 files changed, 478 insertions(+), 239 deletions(-) create mode 100644 doc/contributors/guides/how_to_make_driver.md delete mode 100644 src/backend/doc/howto_make_driver.md diff --git a/doc/contributors/guides/README.md b/doc/contributors/guides/README.md index 6d3e9d827a..88f417d115 100644 --- a/doc/contributors/guides/README.md +++ b/doc/contributors/guides/README.md @@ -2,6 +2,6 @@ This is a collection of development guides that follow the practices, tools and conventions of the project. -1. [How to make a driver.](./making_a_driver.md) +1. [How to make a driver.](./how_to_make_driver.md) > There is also a [video from Eric on this](https://www.youtube.com/watch?v=8znQmrKgNxA) -2. [Passing argumentos to phoenix shell](https://www.youtube.com/watch?v=VDPu7hwBsq8) +2. [Passing arguments to phoenix shell](https://www.youtube.com/watch?v=VDPu7hwBsq8) diff --git a/doc/contributors/guides/how_to_make_driver.md b/doc/contributors/guides/how_to_make_driver.md new file mode 100644 index 0000000000..47d77aeb45 --- /dev/null +++ b/doc/contributors/guides/how_to_make_driver.md @@ -0,0 +1,476 @@ +# How to Make a Puter Driver + +## What is a Driver? + +A driver can be one of two things depending on what you're +talking about: +- a **driver interface** describes a general type of service + and what its parameters and result look like. + For example, `puter-chat-completion` is a driver interface + for AI Chat services, and it specifies that any service + on Puter for AI Chat needs a method called `complete` that + accepts a JSON parameter called `messages`. +- a **driver implementation** exists when a **Service** on + Puter implements a **trait** with the same name as a + driver interface. + +## Part 1: Choose or Create a Driver Interface + +Available driver interfaces exist at this location in the repo: +[/src/backend/src/services/drivers/interfaces.js](../src/services/drivers/interfaces.js). + +When creating a new Puter driver implementation, you should check +this file to see if there's an appropriate interface. We're going +to make a driver that returns greeting strings, so we can use the +existing `hello-world` interface. If there wasn't an existing +interface, it would need to be created. Let's break down this +interface: + +```javascript +'hello-world': { + description: 'A simple driver that returns a greeting.', + methods: { + greet: { + description: 'Returns a greeting.', + parameters: { + subject: { + type: 'string', + optional: true, + }, + }, + result: { type: 'string' }, + } + } +}, +``` + +The **description** describes what the interface is for. This +should be provided that both driver developers and users can +quickly identify what types of services should use it. + +The **methods** object should have at least one entry, but it +may have more. The key of each entry is the name of a method; +in here we see `greet`. Each method also has a description, +a **parameters** object, and a **result** object. + +The **parameters** object has an entry for each parameter that +may be passed to the method. Each entry is an object with a +`type` property specifying what values are allowed, and possibly +an `optional: true` entry. + +All methods for Puter drivers use _named parameters_. There are no +positional parameters in Puter driver methods. + +The **result** object specifies the type of the result. A service +called DriverService will use this to determine the response format +and headers of the response. + +## Part 2: Create a Service + +Creating a service is very easy, provided the service doesn't do +anything. Simply add a class to `src/backend/src/services` or into +the module of your choice (`src/backend/src/modules/`) +that looks like this: + +```javascript +const BaseService = require('./BaseService') +// NOTE: the path specified ^ HERE might be different depending +// on the location of your file. + +class PrankGreetService extends BaseService { +} +``` + +Notice I called the service "PrankGreet". This is a good service +name because you already know what the service is likely to +implement: this service generates a greeting, but it is a greeting +that intends to play a prank on whoever is beeing greeted. + +Then, register the service into a module. If you put the service +under `src/backend/src/services`, then it goes in +[CoreModule](..//src/CoreModule.js) somewhere near the end of +the `install()` method. Otherwise, it will go in the `*Module.js` +file in the module where you placed your service. + +The code to register the service is two lines of code that will +look something like this: + +```javascript +const { PrankGreetServie } = require('./path/to/PrankGreetServie.js'); +services.registerService('prank-greet', PrankGreetServie); +``` + +## Part 3: Verify that the Service is Registered + +It's always a good idea to verify that the service is loaded +when starting Puter. Otherwise, you might spend time trying to +determine why your code doesn't work, when in fact it's not +running at all to begin with. + +To do this, we'll add an `_init` handler to the service that +logs a message after a few seconds. We wait a few seconds so that +any log noise from boot won't bury our message. + +```javascript +class PrankGreetService extends BaseService { + async _init () { + // Wait for 5 seconds + await new Promise(rslv => setTimeout(rslv), 5000); + + // Display a log message + this.log.noticeme('Hello from PrankGreetService!'); + } +} +``` + +Typically you'll use `this.log.info('some message')` in your logs +as opposed to `this.log.noticeme(...)`, but the `noticeme` log +level is helpful when debugging. + +## Part 4: Implement the Driver Interface in your Service + +Now that it has been verified that the service is loaded, we can +start implementing the driver interface we chose eralier. + +```javascript +class PrankGreetService extends BaseService { + async _init () { + // ... same as before + } + + // Now we add this: + static IMPLEMENTS = { + ['hello-world']: { + async greet ({ subject }) { + if ( subject ) { + return `Hello ${subject}, tell me about updog!`; + } + return `Hello, tell me about updog!`; + } + } + } +} +``` + +## Part 5: Test the Driver Implementation + +We have now created the `prank-greet` implementation of `hello-world`. +Let's make a request in the browser to check it out. The example below +is a `fetch` call using `http://api.puter.localhost:4100` as the API +origin, which is the default when you're running Puter's backend locally. + +Also, in this request I refer to `puter.authToken`. If you run this +snippet in the Dev Tools window of your browser from a tab with Puter +open (your local Puter, to be precise), this should contain the current +value for your auth token. + +```javascript +await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'hello-world', + service: 'prank-greet', + method: 'greet', + args: { + subject: 'World', + }, + }), + "method": "POST", +})).json(); +``` + +**You might see a permissions error!** Don't worry, this is expected; +in the next step we'll add the required permissions. + +## Part 6: Permissions + +In the previous step, you will only have gotten a successful response +if you're logged in as the `admin` user. If you're logged in as another +user you won't have access to the service's driver implementations be +default. + +To grant permission for all users, update +[hardcoded-permissions.js](../src/data/hardcoded-permissions.js). + +First, look for the constant `hardcoded_user_group_permissions`. +Whereever you see an entry for `service:hello-world:ii:hello-world`, add +the corresponding entry for your service, which will be called +``` +service:prank-greet:ii:hello-world +``` + +To help you remember the permission string, its helpful to know that +`ii` in the string stands for "invoke interface". i.e. the scope of the +permission is under `service:prank-greet` (the `prank-greet` service) +and we want permission to invoke the interface `hello-world` on that +service. + +You'll notice each entry in `hardcoded_user_group_permissions` has a value +determined by a call to the utility function `policy_perm(...)`. The policy +called `user.es` is a permissive policy for storage drivers, and we can +re-purpose it for our greeting implementor. + +The policy of a permission determines behavior like rate limiting. This is +an advanced topic that is not covered in this guide. + +If you want apps to be able to access the driver implementation without +explicit permission from a user, you will need to also register it in the +`default_implicit_user_app_permissions` constant. Additionally, you can +use the `implicit_user_app_permissions` constant to grant implicit +permission to the builtin Puter apps only. + +Permissions to implementations on services can also be granted at runtime +to a user or group of users using the permissions API. This is beyond the +scope of this guide. + +## Part 7: Verify Successful Response + +If all went well, you should see the response in your console when you +try the request from Part 5. Try logging into a user other than `admin` +to verify permisison is granted. + +```json +"Hello World, tell me about updog!" +``` How to Make a Puter Driver + +## What is a Driver? + +A driver can be one of two things depending on what you're +talking about: +- a **driver interface** describes a general type of service + and what its parameters and result look like. + For example, `puter-chat-completion` is a driver interface + for AI Chat services, and it specifies that any service + on Puter for AI Chat needs a method called `complete` that + accepts a JSON parameter called `messages`. +- a **driver implementation** exists when a **Service** on + Puter implements a **trait** with the same name as a + driver interface. + +## Part 1: Choose or Create a Driver Interface + +Available driver interfaces exist at this location in the repo: +[/src/backend/src/services/drivers/interfaces.js](../src/services/drivers/interfaces.js). + +When creating a new Puter driver implementation, you should check +this file to see if there's an appropriate interface. We're going +to make a driver that returns greeting strings, so we can use the +existing `hello-world` interface. If there wasn't an existing +interface, it would need to be created. Let's break down this +interface: + +```javascript +'hello-world': { + description: 'A simple driver that returns a greeting.', + methods: { + greet: { + description: 'Returns a greeting.', + parameters: { + subject: { + type: 'string', + optional: true, + }, + }, + result: { type: 'string' }, + } + } +}, +``` + +The **description** describes what the interface is for. This +should be provided that both driver developers and users can +quickly identify what types of services should use it. + +The **methods** object should have at least one entry, but it +may have more. The key of each entry is the name of a method; +in here we see `greet`. Each method also has a description, +a **parameters** object, and a **result** object. + +The **parameters** object has an entry for each parameter that +may be passed to the method. Each entry is an object with a +`type` property specifying what values are allowed, and possibly +an `optional: true` entry. + +All methods for Puter drivers use _named parameters_. There are no +positional parameters in Puter driver methods. + +The **result** object specifies the type of the result. A service +called DriverService will use this to determine the response format +and headers of the response. + +## Part 2: Create a Service + +Creating a service is very easy, provided the service doesn't do +anything. Simply add a class to `src/backend/src/services` or into +the module of your choice (`src/backend/src/modules/`) +that looks like this: + +```javascript +const BaseService = require('./BaseService') +// NOTE: the path specified ^ HERE might be different depending +// on the location of your file. + +class PrankGreetService extends BaseService { +} +``` + +Notice I called the service "PrankGreet". This is a good service +name because you already know what the service is likely to +implement: this service generates a greeting, but it is a greeting +that intends to play a prank on whoever is beeing greeted. + +Then, register the service into a module. If you put the service +under `src/backend/src/services`, then it goes in +[CoreModule](..//src/CoreModule.js) somewhere near the end of +the `install()` method. Otherwise, it will go in the `*Module.js` +file in the module where you placed your service. + +The code to register the service is two lines of code that will +look something like this: + +```javascript +const { PrankGreetServie } = require('./path/to/PrankGreetServie.js'); +services.registerService('prank-greet', PrankGreetServie); +``` + +## Part 3: Verify that the Service is Registered + +It's always a good idea to verify that the service is loaded +when starting Puter. Otherwise, you might spend time trying to +determine why your code doesn't work, when in fact it's not +running at all to begin with. + +To do this, we'll add an `_init` handler to the service that +logs a message after a few seconds. We wait a few seconds so that +any log noise from boot won't bury our message. + +```javascript +class PrankGreetService extends BaseService { + async _init () { + // Wait for 5 seconds + await new Promise(rslv => setTimeout(rslv), 5000); + + // Display a log message + this.log.noticeme('Hello from PrankGreetService!'); + } +} +``` + +Typically you'll use `this.log.info('some message')` in your logs +as opposed to `this.log.noticeme(...)`, but the `noticeme` log +level is helpful when debugging. + +## Part 4: Implement the Driver Interface in your Service + +Now that it has been verified that the service is loaded, we can +start implementing the driver interface we chose eralier. + +```javascript +class PrankGreetService extends BaseService { + async _init () { + // ... same as before + } + + // Now we add this: + static IMPLEMENTS = { + ['hello-world']: { + async greet ({ subject }) { + if ( subject ) { + return `Hello ${subject}, tell me about updog!`; + } + return `Hello, tell me about updog!`; + } + } + } +} +``` + +## Part 5: Test the Driver Implementation + +We have now created the `prank-greet` implementation of `hello-world`. +Let's make a request in the browser to check it out. The example below +is a `fetch` call using `http://api.puter.localhost:4100` as the API +origin, which is the default when you're running Puter's backend locally. + +Also, in this request I refer to `puter.authToken`. If you run this +snippet in the Dev Tools window of your browser from a tab with Puter +open (your local Puter, to be precise), this should contain the current +value for your auth token. + +```javascript +await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'hello-world', + service: 'prank-greet', + method: 'greet', + args: { + subject: 'World', + }, + }), + "method": "POST", +})).json(); +``` + +**You might see a permissions error!** Don't worry, this is expected; +in the next step we'll add the required permissions. + +## Part 6: Permissions + +In the previous step, you will only have gotten a successful response +if you're logged in as the `admin` user. If you're logged in as another +user you won't have access to the service's driver implementations be +default. + +To grant permission for all users, update +[hardcoded-permissions.js](../src/data/hardcoded-permissions.js). + +First, look for the constant `hardcoded_user_group_permissions`. +Whereever you see an entry for `service:hello-world:ii:hello-world`, add +the corresponding entry for your service, which will be called +``` +service:prank-greet:ii:hello-world +``` + +To help you remember the permission string, its helpful to know that +`ii` in the string stands for "invoke interface". i.e. the scope of the +permission is under `service:prank-greet` (the `prank-greet` service) +and we want permission to invoke the interface `hello-world` on that +service. + +You'll notice each entry in `hardcoded_user_group_permissions` has a value +determined by a call to the utility function `policy_perm(...)`. The policy +called `user.es` is a permissive policy for storage drivers, and we can +re-purpose it for our greeting implementor. + +The policy of a permission determines behavior like rate limiting. This is +an advanced topic that is not covered in this guide. + +If you want apps to be able to access the driver implementation without +explicit permission from a user, you will need to also register it in the +`default_implicit_user_app_permissions` constant. Additionally, you can +use the `implicit_user_app_permissions` constant to grant implicit +permission to the builtin Puter apps only. + +Permissions to implementations on services can also be granted at runtime +to a user or group of users using the permissions API. This is beyond the +scope of this guide. + +## Part 7: Verify Successful Response + +If all went well, you should see the response in your console when you +try the request from Part 5. Try logging into a user other than `admin` +to verify permisison is granted. + +```json +"Hello World, tell me about updog!" + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/src/backend/doc/howto_make_driver.md b/src/backend/doc/howto_make_driver.md deleted file mode 100644 index ffcc11684d..0000000000 --- a/src/backend/doc/howto_make_driver.md +++ /dev/null @@ -1,237 +0,0 @@ -# How to Make a Puter Driver - -## What is a Driver? - -A driver can be one of two things depending on what you're -talking about: -- a **driver interface** describes a general type of service - and what its parameters and result look like. - For example, `puter-chat-completion` is a driver interface - for AI Chat services, and it specifies that any service - on Puter for AI Chat needs a method called `complete` that - accepts a JSON parameter called `messages`. -- a **driver implementation** exists when a **Service** on - Puter implements a **trait** with the same name as a - driver interface. - -## Part 1: Choose or Create a Driver Interface - -Available driver interfaces exist at this location in the repo: -[/src/backend/src/services/drivers/interfaces.js](../src/services/drivers/interfaces.js). - -When creating a new Puter driver implementation, you should check -this file to see if there's an appropriate interface. We're going -to make a driver that returns greeting strings, so we can use the -existing `hello-world` interface. If there wasn't an existing -interface, it would need to be created. Let's break down this -interface: - -```javascript -'hello-world': { - description: 'A simple driver that returns a greeting.', - methods: { - greet: { - description: 'Returns a greeting.', - parameters: { - subject: { - type: 'string', - optional: true, - }, - }, - result: { type: 'string' }, - } - } -}, -``` - -The **description** describes what the interface is for. This -should be provided that both driver developers and users can -quickly identify what types of services should use it. - -The **methods** object should have at least one entry, but it -may have more. The key of each entry is the name of a method; -in here we see `greet`. Each method also has a description, -a **parameters** object, and a **result** object. - -The **parameters** object has an entry for each parameter that -may be passed to the method. Each entry is an object with a -`type` property specifying what values are allowed, and possibly -an `optional: true` entry. - -All methods for Puter drivers use _named parameters_. There are no -positional parameters in Puter driver methods. - -The **result** object specifies the type of the result. A service -called DriverService will use this to determine the response format -and headers of the response. - -## Part 2: Create a Service - -Creating a service is very easy, provided the service doesn't do -anything. Simply add a class to `src/backend/src/services` or into -the module of your choice (`src/backend/src/modules/`) -that looks like this: - -```javascript -const BaseService = require('./BaseService') -// NOTE: the path specified ^ HERE might be different depending -// on the location of your file. - -class PrankGreetService extends BaseService { -} -``` - -Notice I called the service "PrankGreet". This is a good service -name because you already know what the service is likely to -implement: this service generates a greeting, but it is a greeting -that intends to play a prank on whoever is beeing greeted. - -Then, register the service into a module. If you put the service -under `src/backend/src/services`, then it goes in -[CoreModule](..//src/CoreModule.js) somewhere near the end of -the `install()` method. Otherwise, it will go in the `*Module.js` -file in the module where you placed your service. - -The code to register the service is two lines of code that will -look something like this: - -```javascript -const { PrankGreetServie } = require('./path/to/PrankGreetServie.js'); -services.registerService('prank-greet', PrankGreetServie); -``` - -## Part 3: Verify that the Service is Registered - -It's always a good idea to verify that the service is loaded -when starting Puter. Otherwise, you might spend time trying to -determine why your code doesn't work, when in fact it's not -running at all to begin with. - -To do this, we'll add an `_init` handler to the service that -logs a message after a few seconds. We wait a few seconds so that -any log noise from boot won't bury our message. - -```javascript -class PrankGreetService extends BaseService { - async _init () { - // Wait for 5 seconds - await new Promise(rslv => setTimeout(rslv), 5000); - - // Display a log message - this.log.noticeme('Hello from PrankGreetService!'); - } -} -``` - -Typically you'll use `this.log.info('some message')` in your logs -as opposed to `this.log.noticeme(...)`, but the `noticeme` log -level is helpful when debugging. - -## Part 4: Implement the Driver Interface in your Service - -Now that it has been verified that the service is loaded, we can -start implementing the driver interface we chose eralier. - -```javascript -class PrankGreetService extends BaseService { - async _init () { - // ... same as before - } - - // Now we add this: - static IMPLEMENTS = { - ['hello-world']: { - async greet ({ subject }) { - if ( subject ) { - return `Hello ${subject}, tell me about updog!`; - } - return `Hello, tell me about updog!`; - } - } - } -} -``` - -## Part 5: Test the Driver Implementation - -We have now created the `prank-greet` implementation of `hello-world`. -Let's make a request in the browser to check it out. The example below -is a `fetch` call using `http://api.puter.localhost:4100` as the API -origin, which is the default when you're running Puter's backend locally. - -Also, in this request I refer to `puter.authToken`. If you run this -snippet in the Dev Tools window of your browser from a tab with Puter -open (your local Puter, to be precise), this should contain the current -value for your auth token. - -```javascript -await (await fetch("http://api.puter.localhost:4100/drivers/call", { - "headers": { - "Content-Type": "application/json", - "Authorization": `Bearer ${puter.authToken}`, - }, - "body": JSON.stringify({ - interface: 'hello-world', - service: 'prank-greet', - method: 'greet', - args: { - subject: 'World', - }, - }), - "method": "POST", -})).json(); -``` - -**You might see a permissions error!** Don't worry, this is expected; -in the next step we'll add the required permissions. - -## Part 6: Permissions - -In the previous step, you will only have gotten a successful response -if you're logged in as the `admin` user. If you're logged in as another -user you won't have access to the service's driver implementations be -default. - -To grant permission for all users, update -[hardcoded-permissions.js](../src/data/hardcoded-permissions.js). - -First, look for the constant `hardcoded_user_group_permissions`. -Whereever you see an entry for `service:hello-world:ii:hello-world`, add -the corresponding entry for your service, which will be called -``` -service:prank-greet:ii:hello-world -``` - -To help you remember the permission string, its helpful to know that -`ii` in the string stands for "invoke interface". i.e. the scope of the -permission is under `service:prank-greet` (the `prank-greet` service) -and we want permission to invoke the interface `hello-world` on that -service. - -You'll notice each entry in `hardcoded_user_group_permissions` has a value -determined by a call to the utility function `policy_perm(...)`. The policy -called `user.es` is a permissive policy for storage drivers, and we can -re-purpose it for our greeting implementor. - -The policy of a permission determines behavior like rate limiting. This is -an advanced topic that is not covered in this guide. - -If you want apps to be able to access the driver implementation without -explicit permission from a user, you will need to also register it in the -`default_implicit_user_app_permissions` constant. Additionally, you can -use the `implicit_user_app_permissions` constant to grant implicit -permission to the builtin Puter apps only. - -Permissions to implementations on services can also be granted at runtime -to a user or group of users using the permissions API. This is beyond the -scope of this guide. - -## Part 7: Verify Successful Response - -If all went well, you should see the response in your console when you -try the request from Part 5. Try logging into a user other than `admin` -to verify permisison is granted. - -```json -"Hello World, tell me about updog!" -``` From 0872ef93649b6a09b20746c309ac97afbe303844 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 17:17:53 -0300 Subject: [PATCH 07/11] doc(contrib): link contrib guidelines from readme add oscon --- doc/contributors/README.md | 4 ++ doc/contributors/oscon.md | 127 +++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 doc/contributors/oscon.md diff --git a/doc/contributors/README.md b/doc/contributors/README.md index bc618f1691..23e134c13e 100644 --- a/doc/contributors/README.md +++ b/doc/contributors/README.md @@ -28,3 +28,7 @@ You will be able to find existing documentation on a contribution topic **follow Also, comments uses prefixes for improve their clearness. [`Here you will find the standard`](./comment_prefixes.md) that is followed. + +## How to interact with the puter team and other contributors + +[`Here you will find our colaboration guidelines`](./oscon.md) so you can get started. diff --git a/doc/contributors/oscon.md b/doc/contributors/oscon.md new file mode 100644 index 0000000000..477566a97d --- /dev/null +++ b/doc/contributors/oscon.md @@ -0,0 +1,127 @@ +# Contributing to Puter + +Welcome to Puter, the open-source distributed internet operating system. We're excited to have you contribute to our project, whether you're reporting bugs, suggesting new features, or contributing code. This guide will help you get started with contributing to Puter in different ways. + +
+ +# Report bugs + +Before reporting a bug, please check our [the issues on our GitHub repository](https://github.com/HeyPuter/puter/issues) to see if the bug has already been reported. If it has, you can add a comment to the existing issue with any additional information you have. + +If you find a new bug in Puter, please [open an issue on our GitHub repository](https://github.com/HeyPuter/puter/issues/new). We'll do our best to address the issue as soon as possible. When reporting a bug, please include as much information as possible, including: + +- A clear and descriptive title +- A description of the issue +- Steps to reproduce the bug +- Expected behavior +- Actual behavior +- Screenshots, if applicable +- Your host operating system and browser +- Your Puter version, location, ... + +Please open a separate issue for each bug you find. + +Maintainers will apply the appropriate labels to your issue. + +
+ +# Suggest new features + +If you have an idea for a new feature in Puter, please open a new discussion thread on our [GitHub repository](https://github.com/HeyPuter/puter/discussions) to discuss your idea with the community. We'll do our best to respond to your suggestion as soon as possible. + +When suggesting a new feature, please include as much information as possible, including: + +- A clear and descriptive title +- A description of the feature +- The problem the feature will solve +- Any relevant screenshots or mockups +- Any relevant links or resources + +
+ +# Contribute code + +If you'd like to contribute code to Puter, you need to fork the project and submit a pull request. If this is your first time contributing to an open-source project, we recommend reading this short guide by GitHub on [how to contribute to a project](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project). + +We'll review your pull request and work with you to get your changes merged into the project. + +## Repository Structure + +![file structure](./doc/File%20Structure.drawio.png) + +## Your first code contribution + +We maintain a list of issues that are good for first-time contributors. You can find these issues by searching for the [`good first issue`](https://github.com/HeyPuter/puter/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label in our [GitHub repository](https://github.com/HeyPuter/puter). These issues are designed to be relatively easy to fix, and we're happy to help you get started. Pick an issue that interests you, and leave a comment on the issue to let us know you're working on it. + +## Documentation for Contributors + +### Backend +See [src/backend/CONTRIBUTING.md](src/backend/CONTRIBUTING.md) + +
+ +## 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) + +
+ +## Commit Messages + +**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. + +### Conventional Commits +We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) with the following prefixes: +- `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: +- If the commit message is in _past tense_, it's a shorthand for the following: + - `dev: apply changes that would be applied after one had ` +- If the commit message is in _present tense_, it's shorthand for the following: + - `dev: apply changes that would be applied after ` + +For example, the following are correct: +- `dev: improved readdir` + - interpret this as: `dev: apply changes that would be applied after one had improved readdir` +- `dev: improving readdir` + - interpret this as: `dev: apply changes that would be applied after improving readdir` + +
+ +## Code Review + +Once you've submitted your pull request, the project maintainers will review your changes. We may suggest some changes or improvements. This is a normal part of the process, and your contributions are greatly appreciated! + +
+ +## Contribution License Agreement (CLA) + +Like many open source projects, we require contributors to sign a Contribution License Agreement (CLA) before we can accept your code. When you open a pull request for the first time, a bot will automatically add a comment with a link to the CLA. You can sign the CLA electronically by following the link and filling out the form. + +
+ +# Getting Help + +If you have any questions about Puter, please feel free to reach out to us through the following channels: + +- [Discord](https://discord.com/invite/PQcx7Teh8u) +- [Reddit](https://www.reddit.com/r/Puter/) +- [Twitter](https://twitter.com/HeyPuter) +- [Email](mailto:support@puter.com) + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. From fe8c66e34640a3dc1fa90698767d4a49184093d5 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 17:30:21 -0300 Subject: [PATCH 08/11] doc(contrib): link support document from readme add support --- doc/contributors/README.md | 4 ++++ doc/contributors/support.md | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 doc/contributors/support.md diff --git a/doc/contributors/README.md b/doc/contributors/README.md index 23e134c13e..11e4557064 100644 --- a/doc/contributors/README.md +++ b/doc/contributors/README.md @@ -32,3 +32,7 @@ Also, comments uses prefixes for improve their clearness. ## How to interact with the puter team and other contributors [`Here you will find our colaboration guidelines`](./oscon.md) so you can get started. + +## Get support + +Keep in touch [by using these means of contact](./support.md) diff --git a/doc/contributors/support.md b/doc/contributors/support.md new file mode 100644 index 0000000000..3f5d2ac4ad --- /dev/null +++ b/doc/contributors/support.md @@ -0,0 +1,17 @@ +# Support + +Connect with the maintainers and community through these official channels: + +- Bug report or feature request? Please [open an 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) +- Security issues? [security@puter.com](mailto:security@puter.com) +- Email maintainers at [hi@puter.com](mailto:hi@puter.com) + +We are always happy to help you with any questions you may have. Don't hesitate to ask! + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. From 50872c62ea5fe498959eb513b6b2261e70147a12 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 17:38:51 -0300 Subject: [PATCH 09/11] doc(contrib): update document on contrib on docs --- doc/contributors/contribute_on_docs.md | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 doc/contributors/contribute_on_docs.md diff --git a/doc/contributors/contribute_on_docs.md b/doc/contributors/contribute_on_docs.md new file mode 100644 index 0000000000..52ef33f1f4 --- /dev/null +++ b/doc/contributors/contribute_on_docs.md @@ -0,0 +1,41 @@ +# This documentation + +## About + +This documentation tries to gather in an easy to navigate place for a developer (no matter his area of work, it can be frontend, backend, devops, etc...) the documentation related to the development of the opensource Puter project. + +General documentation is located in the ‘doc/’ directory while specific documentation is kept in the directories closest to what it documents. + +Documentation runs on mkdocs tool, an easy and powerful documentation tool written in Python. It was decided to use this tool since most of the existing documentation was in markdown format, and seeing that new contributors were also adding new documentation in markdown format. + +## Documentation in the repository + +The documentation can be accessed through [the official project repository Wiki](https://github.com/HeyPuter/puter/wiki). This is since commit 99684d8. + +## Get started with docs + +1. Clone puter's repo. +2. Install mkdocs and mkdocs-material. +``` +pip install mkdocs && pip install mkdocs-material +``` +3. Navigate to the doc/ directory. +4. Build the documentation +``` +mkdocs build && mkdocs serve +``` +5. Now you should have it live on the IP http://127.0.0.1:8000 + +In the ```doc/``` directory you will find all the source files of the documentation in markdown format. You can edit them and create new ones under that directory, and incorporate them into the documentation either using the navbar of the documentation (see the doc/dev_doc/mkdocs.yml file) or using internal links with markdown. + +--- + +Using mkdocs you can install themes. For this documentation, you will need to install material theme: + +``` +pip install mkdocs-material +``` + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. From 8a0931dad9bf8487787df6c767cb9709ddd37dc3 Mon Sep 17 00:00:00 2001 From: jose Date: Thu, 27 Feb 2025 17:49:51 -0300 Subject: [PATCH 10/11] doc(development): create general development docs --- doc/development/arch.md | 153 +++++++++++++++++++++++++++++++++++++ doc/development/glosary.md | 28 +++++++ doc/development/roadmap.md | 8 ++ doc/development/stack.md | 95 +++++++++++++++++++++++ 4 files changed, 284 insertions(+) create mode 100644 doc/development/arch.md create mode 100644 doc/development/glosary.md create mode 100644 doc/development/roadmap.md create mode 100644 doc/development/stack.md diff --git a/doc/development/arch.md b/doc/development/arch.md new file mode 100644 index 0000000000..a9642c0fea --- /dev/null +++ b/doc/development/arch.md @@ -0,0 +1,153 @@ +# System Architecture + +## General + +Puter's system goals is to provide an internet operating system, providing (as brief): + +1. **User management:** (User) Account and session CrUD, Permissions... +2. **Desktop environment use:** (User) Use apps in interactive mode through GUIs, CrUD symbolic links and icons... +3. **System deployment:** (Developers) build a web app, or web service, on puter. + +and ensuring: + + 1. **Extensibility:** you should be able to create your own Kernel Modules, user-oriented applications, and so. + 2. **Debuggability:** given this is opensource-driven, you'll find loggers and monitoring tools aiming to make development easier. + 3. **Deployability:** you, and other users, should be able to deploy this system at least both self host and public hosting. + 4. **Securability:** you, and other users, should be able to trust on puter as a personal cloud, a remote desktop for servers and workstations, and as a software development platform. + +In order to achieve those requirements, Puter is following (tl;dr): + +1. **A client-server style Architecture:** Allow user to interact with system GUI through a Web Browser (as an external system). +2. **Micro-kernel pattern:** Allow backend (in which heavy processing occurs) to extend system's functionality, keeping the core of the system and the other additions decoupled each other. + +In in a nutshell: +``` + Puter is Puter, whatever you think it might be useful for + you can use it for. You can think of it as a high-level + operating system where the "hardware" is external services or + resources provided by the host OS; if you develop apps on + this platform you have higher-level primitives, like how + using AI services is considered a "driver", or how Puter's + filesystem can use a database to store the directory tree and + file metadata. +``` + +## Deployment + +### Local dev + +Get the [monorepo](https://github.com/HeyPuter/puter/), and then run `install` and `start` [npm scripts](https://github.com/HeyPuter/puter/blob/main/package.json) + +``` +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +You get in error? then you can [check our first run issues checklist.](../self-hosters/first-run-issues.md) + +Also, if you get "Cannot write to path" error, it usually happens when /var/puter isn\'t chown\'d to the right UID. You can check the [issue number 645.](https://github.com/HeyPuter/puter/issues/645) +### Docker + +On linux/macOS run: + +``` +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 +``` + +On Windows run: + +``` +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 +``` + +## Main modules traits + +### service + +- **Concern:** to extend core functionality. +- **Class:** BaseService (extends concepts.Service) +- **Public interface:** + +``` +/** +* Creates the service's data structures and initial values. +* This method sets up logging and error handling, and calls a custom `_construct` method if defined. +* +* @returns {Promise} A promise that resolves when construction is complete. +*/ +async construct () => void +``` + +``` +/** +* Constructs service class using Service Resources list +* Service Resources properties: services, config, my_config, name, args, context. +*/ +constructor (service_resources, ...a) +``` + + +``` +/** +* Performs service lifecycle's initialization phase +*/ +async init () => void +``` + +### Kernel + + +- **Concern:** To orchestrate core modules for system to load up, following [**Backend Boot Sequence**.](../../src/backend/doc/contributors/boot-sequence.md) +- **Class:** Kernel (extends AdvancedBase) +- **Public interface:** + +``` +/** +* Construct kernel module configuring its useapi and entry path +*/ +constructor (entry_path) => +``` + + +``` +/** +* Adds a module into kernel's modules list +*/ +add_module (module) => void +``` + +``` +/** +* Boots backend +*/ +boot () => void +``` + +## System entry points + +### Testing +Mocha is being used for this. +There are 2 main **test directories:** +1. src/phoenix/test -> testing phoenix emulator. +2. src/backend/tools/test -> a set of tools for backend testing. [Read more about backend tools.](../../src/backend/doc/contributors/testing_tools.md ) + +### Use cases +For **self hosting** deployment, there is a _tool_ called "run-selfhosted.js" which you can run with ```npm run start``` command. That tool is going to: + +1. Get all required _kernel modules_ from the **@heyputer/backend npm package** +2. Configure kernel's entry path as the directory path of the current file (so, the run-selfhosted tool's directory). +3. Add all required _kernel modules_ to kernel's modules list. +4. Start kernel by its ```boots()``` public method. + +**Monitoring:** The ```SelfHostedModule``` is responsible for load 3 project's module watching tools (for GUI, TERMINAL, EMULATOR, GIT, PHOENIX, and PUTER-JS) + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/development/glosary.md b/doc/development/glosary.md new file mode 100644 index 0000000000..89fbf2cd50 --- /dev/null +++ b/doc/development/glosary.md @@ -0,0 +1,28 @@ +# Puter's glosary + +## General + +1. **Puter:** Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. + +2. **Self hosting:** Means running and managing the app on your infrastructure instead of using thid-party hosting service. +You can learn more on how to self host your Puter instance [here](./deployment/self_host.md) + +3. **Kernel:** It is a simple module which is in charge of orchestrating the initialization of the system, following the boot sequence. Following the [Microkernel pattern](https://www.oreilly.com/library/view/software-architecture-patterns/9781098134280/ch04.html), this module corresponds to the Core of Puter backend. + +4. **Monorepo:** A centralised source code repository made of several interrelated packages. + +5. **npm workspace:** An NPM workspace is a NPM feature that allows you to **manage multiple related packages** (like a monorepo) within a single repository. + +## Backend components + +1. **BasicBase:** Abstract class with inheritance tracking for composite the system using shared configuration and behaviors. +2. **FeatureBase:** Extending BasicBase, allows defining and install features (classes and modules) as TopicsFeature, MariMethodsfeature, and others. +3. **AdvancedBase:** Extending FeatureBase, Defines features to be installed by Its FeatureBase parent instance. + +> As you can see, components follows an inheritance chain which starts in BasicBase. + +4. **KernelModule:** Extending AdvancedBase, orchestrate system boot sequence. + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/development/roadmap.md b/doc/development/roadmap.md new file mode 100644 index 0000000000..05e60bd8f1 --- /dev/null +++ b/doc/development/roadmap.md @@ -0,0 +1,8 @@ +# What next? + +This is a project under development with current working releases [check our changelog.](https://github.com/HeyPuter/puter/releases/) +This documentation is under development too, and you could improve it with your pr. + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. diff --git a/doc/development/stack.md b/doc/development/stack.md new file mode 100644 index 0000000000..a2dabb1997 --- /dev/null +++ b/doc/development/stack.md @@ -0,0 +1,95 @@ +# Stack of puter + +Puter source is modular, meaning that there are a **node module for each src/ folder subdirectory**. +That means each module could be defining its own package dependency list. + +## General + +1. Using Javascript as main language. +2. Using DHTML (html,js,css) for dinamic web rendering. +3. Using Shell and Docker for building and deployment scripts. +4. Using Docker for containerized deployment. +5. Using SQLITE for persistence (of sessions, app storage...) +6. Using local disk for some storage operations. + +## Node related + +Puter currently Node-related stack is: + +### DevDependencies + +1. **[@eslint/js](https://eslint.org/docs/latest/)** + Official ESLint extension to handle JavaScript specific rules. + +2. **[chalk](https://github.com/chalk/chalk)** + Allows formating terminal output with colors and styles. + +3. **[clean-css](https://github.com/clean-css/clean-css)** + Efficient CSS minifier. + +4. **[dotenv](https://github.com/motdotla/dotenv#readme)** + Load environment variables from a `.env` file into `process.env`. + +5. **[eslint](https://eslint.org/docs/latest/)** + Static analysis tool to find and fix problems in JavaScript code. + +6. **[express](https://expressjs.com/)** + Minimalistic framework for building web applications in Node.js. + +7. **[globals](https://github.com/sindresorhus/globals#readme)** + List of global variables recognized in different environments. + +8. **[html-entities](https://github.com/mdevils/html-entities#readme)** + Encodes and decodes HTML entities in JavaScript. + +9. **[html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin#readme)** + Automatically generates HTML files for Webpack projects. + +10. **[license-check-and-add](https://github.com/mjhenkes/license-check-and-add#readme)** + Automatically checks and adds licenses to project files. + +11. **[mocha](https://mochajs.org/)** + JavaScript testing framework with support for asynchronous testing. + +12. **[nodemon](https://github.com/remy/nodemon#readme)** + Automatically reloads a Node.js application when it detects code changes. + +13. **[uglify-js](https://github.com/mishoo/UglifyJS#readme)** + Minifies and optimizes JavaScript code to reduce its size. + +14. **[webpack](https://webpack.js.org/)** + Module packer for JavaScript. + +### Dependencies + +16. **[javascript-time-ago](https://github.com/catamphetamine/javascript-time-ago#readme)** + Friendly formatting of dates and times in different languages. + +17. **[json-colorizer](https://github.com/kaelzhang/node-json-colorizer#readme)** + Format and colorize JSON output in the terminal. + +18. **[open](https://github.com/sindresorhus/open#readme)** + Opens default URLs, files or applications from Node.js. + +19. **[sharp](https://sharp.pixelplumbing.com/)** + Fast and optimized image processing library for Node.js. + +20. **[sharp-bmp](https://github.com/karaggeorge/sharp-bmp#readme)** + Sharp extension to handle BMP images. + +21. **[sharp-ico](https://github.com/karaggeorge/sharp-ico#readme)** + Sharp extension to handle ICO images. + +22. **[simple-git](https://github.com/steveukx/git-js#readme)** + Simple interface to work with Git in Node.js. + +23. **[string-template](https://github.com/Matt-Esch/string-template#readme)** + Simple string-based template engine. + +24. **[uuid](https://github.com/uuidjs/uuid#readme)** + Unique generator of UUID identifiers according to RFC standards. + + +--- + +If you find any bug or error in this documentation, do not hesitate to send your complaint to **jose.s.contacto@gmail.com**, or **colaborate** with the documentation yourself. From 4ad5f6d2613a0f65bb4c2202f09f21e0dffae7e9 Mon Sep 17 00:00:00 2001 From: jose Date: Tue, 11 Mar 2025 22:06:28 -0300 Subject: [PATCH 11/11] doc(mkdocs): Create script for automate mkdocs updation --- doc/update_mkdocs.py | 97 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 doc/update_mkdocs.py diff --git a/doc/update_mkdocs.py b/doc/update_mkdocs.py new file mode 100644 index 0000000000..aa46017e84 --- /dev/null +++ b/doc/update_mkdocs.py @@ -0,0 +1,97 @@ +# Script for update documentation used by mkdocs + + +from os import path, listdir, mkdir +import subprocess + +# TODO: 0. Get project documentation path +# TODO: Load it up from a config file + +DOCS_PATH = "doc/" +MKDOCS_PATH = "mkdocs.yml" +STATIC_DOCS_PATH = "static_documentation" + +## Ensure there is a folder for static documentation. +## NOTE: This is not being used when mkdocs runs as server +if not path.exists(STATIC_DOCS_PATH): + mkdir(STATIC_DOCS_PATH) + print(f"Directory '{STATIC_DOCS_PATH}' created successfully") +else: + print(f"Directory '{STATIC_DOCS_PATH}' already exists, using it") + +# TODO: 1. Get mkdocs.yml template + +docs_title = str() +nav_sections = dict() + +DOCS_CONFIG = { + "name": "material", + "palette": { + "primary": "indigo", + "accent": "pink", + "toggle": { + "icon": "material/weather-sunny", + "name": "Switch to dark mode" + }, + "scheme": "default" + } +} + +# TODO: 2. Render a document with actual state for that template +# - Read subdir of doc as categories +# TODO: Obtain current repo version (to let reader to know what version the doc is aiming to). This could be done using git tags. + +docs_title = "Puter v2.5.1 development documentation" + +categories = [category for category in listdir(DOCS_PATH) if path.isdir(path.join(DOCS_PATH, category))] + +print(f"DOC: Updating MKDOCS documentation for the following categories: {', '.join(categories)}") +# - Create navbar using categories (assuming each one has a README) +for category in categories: + category_path = f"{category}/README.md" + nav_sections[" - "+category] = category_path + +DOCUMENT_TEMPLATE = { + "docs_dir" : DOCS_PATH, + "site_dir" : STATIC_DOCS_PATH, + "site_name" : docs_title, + "nav" : nav_sections, + "theme" : DOCS_CONFIG, +} +print(DOCUMENT_TEMPLATE) + + +# TODO: 3. Replace mkdocs document if exists, else create one +def dict_to_yaml(data, indent=0): + yaml_str = "" + spaces = " " * indent # Defining indentation. + + if isinstance(data, dict): + for key, value in data.items(): + yaml_str += f"{spaces}{key}:" + if isinstance(value, (dict, list)): # If value is nested, use recursion + yaml_str += "\n" + dict_to_yaml(value, indent + 1) + else: + yaml_str += f" {value}\n" + + elif isinstance(data, list): + for item in data: + yaml_str += f"{spaces}- " + if isinstance(item, (dict, list)): + yaml_str += "\n" + dict_to_yaml(item, indent + 1) + else: + yaml_str += f"{item}\n" + + return yaml_str + +document_string = dict_to_yaml(DOCUMENT_TEMPLATE) +print(document_string) + +def create_mkdocs_file(content): + + with open(MKDOCS_PATH, "w") as file: # NOTE: this is overriding mkdoc file if exists, this avoids a lot of issues. + file.write(content) + + print(f"File '{MKDOCS_PATH}' created successfully.") + +create_mkdocs_file(document_string)