Introduction

Welcome back, aspiring Puter.js developer! In the previous chapters, we laid the groundwork by understanding what Puter.js is and setting up our development environment. You’re now ready to roll up your sleeves and interact directly with the Puter.js Web OS.

This chapter is all about getting to know the Puter.js Core APIs. Think of these APIs as the essential tools and commands that allow your applications to communicate with the Puter.js system itself. We’ll learn how to fetch system information, display messages, get user input, and even listen for important system events. Mastering these foundational APIs is crucial, as they form the bedrock for building any interactive and robust Puter.js application.

By the end of this chapter, you’ll be comfortable using the core Puter global object and its key modules to make your apps come alive. Get ready to start coding and see your Puter.js applications begin to interact with their environment!

Core Concepts: Your App’s Gateway to the Web OS

At the heart of every Puter.js application is a global JavaScript object, simply named Puter. This Puter object is your application’s exclusive gateway to the underlying Web OS functionalities. It’s similar to how window or document provide access to browser APIs, but Puter provides access to the specialized services of the Puter.js environment.

Let’s explore some of the most fundamental modules available through the Puter object.

The Puter.system Module: Peeking Under the Hood

The Puter.system module provides access to information about the Puter.js operating system and the environment your app is running in. This is incredibly useful for tailoring your application’s behavior based on system capabilities or for debugging purposes.

Puter.system.info()

This asynchronous method returns a Promise that resolves with an object containing various details about the Puter.js environment. This might include the Puter.js version, current user details (if authenticated), available memory, and more.

Why is this important? Imagine you want your app to behave differently if it’s running on a mobile Puter.js client versus a desktop one, or if you need to report system diagnostics. Puter.system.info() gives you that data.

Puter.system.version

A synchronous property that provides the current version string of the Puter.js runtime. As of 2026-01-12, Puter.js is stable at v1.x, with v1.2.0 being the widely adopted stable release for production environments.

The Puter.ui Module: Interacting with the User

User interaction is key to any application. The Puter.ui module provides a set of standardized, system-level dialogs that ensure a consistent user experience across all Puter.js applications. These are not just window.alert or window.prompt; these are styled and managed by the Puter.js Web OS itself.

Puter.ui.alert(message, [title])

Displays a simple alert dialog to the user with a specified message. You can optionally provide a title for the dialog. This method returns a Promise that resolves when the user dismisses the alert.

Why is this important? For critical notifications, error messages, or simple confirmations that don’t require a “Yes/No” decision, Puter.ui.alert is your go-to.

Puter.ui.prompt(message, [defaultValue], [title])

Presents a prompt dialog to the user, asking for text input. The message explains what input is needed, and defaultValue can pre-fill the input field. An optional title can be provided. This method returns a Promise that resolves with the user’s input string, or null if the user cancels.

Why is this important? When you need to gather specific textual information from the user, like their name, a file name, or a configuration value, Puter.ui.prompt is perfect.

Puter.ui.confirm(message, [title])

Displays a confirmation dialog with “Yes” and “No” (or “OK” and “Cancel”) buttons. The message explains the action being confirmed, and an optional title can be set. This method returns a Promise that resolves to true if the user confirms, and false if they cancel.

Why is this important? For actions that have significant consequences, like deleting data or proceeding with a complex operation, Puter.ui.confirm provides a clear decision point for the user.

The Puter.events Module: Responding to the System

The Puter.events module allows your application to listen for and react to system-wide events or events specific to your application’s lifecycle within the Puter.js environment. This is a powerful mechanism for building responsive and integrated applications.

Puter.events.on(eventName, listener)

Registers an event listener function that will be called whenever eventName occurs. The listener function receives event-specific data as arguments. Common events include app:ready (when your app is fully loaded and ready), user:login, user:logout, or custom events defined by other Puter.js components.

Why is this important? Event-driven programming is fundamental to modern applications. It allows your app to react dynamically to changes in the user’s session, system state, or interactions with other applications without constantly polling for updates.

Step-by-Step Implementation: Your First Core API Interactions

Let’s put these concepts into practice. We’ll create a simple Puter.js application that uses Puter.system and Puter.ui to get some information and interact with the user.

First, ensure you have your basic index.html and script.js set up as described in Chapter 3. We’ll be adding all our code to script.js.

1. Getting System Information

Let’s start by fetching and displaying some system information when our app loads.

In your script.js file, add the following code:

// script.js

// Using an async function to handle Promises returned by Puter APIs
async function initializeApp() {
    console.log("Puter.js app is starting...");

    // Accessing a synchronous property
    console.log(`Puter.js Version: ${Puter.system.version}`);

    // Fetching asynchronous system information
    try {
        const systemInfo = await Puter.system.info();
        console.log("Full System Information:", systemInfo);
        // We can display a simple alert with some info
        Puter.ui.alert(`Welcome to Puter.js!\nRunning on: ${systemInfo.platform}\nVersion: ${systemInfo.puterVersion}`, "System Info");
    } catch (error) {
        console.error("Failed to get system information:", error);
        Puter.ui.alert("Could not retrieve system information. Please check console for details.", "Error");
    }
}

// Call the initialization function
initializeApp();

Explanation:

  • We wrap our logic in an async function called initializeApp. This is a modern JavaScript best practice for handling asynchronous operations (like Puter.system.info() which returns a Promise) using await.
  • console.log("Puter.js Version: ${Puter.system.version}"); directly accesses the synchronous version property and logs it.
  • const systemInfo = await Puter.system.info(); pauses the execution until the Puter.system.info() Promise resolves, then stores the returned object in systemInfo.
  • Puter.ui.alert(...) is then used to display a friendly welcome message using data from systemInfo.
  • A try...catch block is essential for robust error handling, especially with asynchronous operations that might fail.
  • Finally, initializeApp(); kicks off our app’s logic.

Run your Puter.js app (e.g., using puter run from your development environment). You should see an alert dialog appear with system information, and messages in your Puter.js developer console.

2. Interacting with the User via UI Dialogs

Now, let’s add some user interaction using Puter.ui.prompt and Puter.ui.confirm. We’ll modify our initializeApp function.

Update your script.js to include the following additions after the Puter.ui.alert call for system info, but still within the try block:

// script.js

async function initializeApp() {
    console.log("Puter.js app is starting...");

    console.log(`Puter.js Version: ${Puter.system.version}`);

    try {
        const systemInfo = await Puter.system.info();
        console.log("Full System Information:", systemInfo);
        Puter.ui.alert(`Welcome to Puter.js!\nRunning on: ${systemInfo.platform}\nVersion: ${systemInfo.puterVersion}`, "System Info");

        // --- New code for user interaction ---

        // Ask the user for their name
        const userName = await Puter.ui.prompt("What's your name, explorer?", "Guest", "Identify Yourself");
        if (userName) {
            console.log(`User entered name: ${userName}`);
            Puter.ui.alert(`Hello, ${userName}! Glad to have you here.`, "Greeting");

            // Ask for confirmation
            const proceed = await Puter.ui.confirm("Shall we proceed to the next step?", "Confirmation");
            if (proceed) {
                console.log("User confirmed to proceed.");
                Puter.ui.alert("Great! Let's continue our journey.", "Next Step");
            } else {
                console.log("User cancelled.");
                Puter.ui.alert("No worries! You can restart anytime.", "Cancelled");
            }
        } else {
            console.log("User cancelled name input.");
            Puter.ui.alert("No name provided. Proceeding as Anonymous.", "Greeting");
        }

        // --- End of new code ---

    } catch (error) {
        console.error("Failed to get system information or handle UI interaction:", error);
        Puter.ui.alert("An error occurred during app initialization. Please check console for details.", "Error");
    }
}

initializeApp();

Explanation of new parts:

  • const userName = await Puter.ui.prompt(...): This line prompts the user for their name. The await ensures that the script waits for the user to enter text or cancel before continuing. "Guest" is provided as a default value.
  • if (userName): We check if userName has a value (meaning the user entered something and didn’t cancel). If userName is null, the user canceled the prompt.
  • const proceed = await Puter.ui.confirm(...): This line presents a confirmation dialog. proceed will be true if the user clicks “Yes” and false if they click “No” (or “Cancel”).
  • Conditional alerts are then displayed based on the user’s choices, demonstrating how to branch logic.

Run your app again. You’ll now experience a sequence of dialogs: the system info alert, a prompt for your name, a greeting, a confirmation dialog, and a final message based on your choice.

3. Basic Event Handling with Puter.events.on

Finally, let’s explore how to listen for a system event. A common and useful event is app:ready, which fires when your Puter.js application has fully loaded and is ready for interaction.

Add the following code to your script.js, preferably at the top level, outside the initializeApp function, but before it’s called:

// script.js

// Listen for the 'app:ready' event
Puter.events.on('app:ready', () => {
    console.log("Puter.js 'app:ready' event fired! The application is fully loaded.");
    // This is a great place to start your main application logic
    initializeApp(); // Call our main initialization function here
});

// Remove the direct call to initializeApp() from the end
// initializeApp(); // Comment out or remove this line

Explanation:

  • Puter.events.on('app:ready', () => { ... }); registers a listener. The provided arrow function will execute once the app:ready event is emitted by the Puter.js runtime.
  • We’ve moved the call to initializeApp() inside this event listener. This is a best practice: it ensures your main application logic only runs when the Puter.js environment is fully initialized and ready, preventing potential issues with APIs not being available yet.
  • Remember to remove or comment out the standalone initializeApp(); call if you’re moving it inside the event listener to avoid calling it twice.

Now, when you run your app, initializeApp will only be called after the app:ready event confirms the Puter.js environment is fully prepared. You’ll see the “app:ready” log message before your system info alert.

Mini-Challenge: Personal Welcome App

Ready for a small challenge to solidify your understanding?

Challenge: Create a Puter.js application that does the following:

  1. When the app is ready, it should first greet the user with a Puter.ui.alert saying “Welcome to your personal Puter.js experience!”.
  2. Immediately after the welcome, it should use Puter.ui.prompt to ask the user, “What is your favorite Puter.js feature so far?”
  3. If the user provides an answer, display a Puter.ui.alert thanking them: “Thanks for sharing! You chose: [User’s Answer]”.
  4. If the user cancels the prompt, display a Puter.ui.alert saying “No worries! Feel free to explore more features.”
  5. Finally, use Puter.ui.confirm to ask “Would you like to see the current Puter.js version?” If they confirm, show a Puter.ui.alert with Puter.system.version. Otherwise, show an alert “Understood. See you next time!”

Hint: Remember to use async/await for all Puter.ui calls, and structure your logic within the app:ready event listener. Think about the flow and how if statements can help you respond to user choices.

What to observe/learn: This challenge helps you practice chaining multiple Puter.ui interactions, handling user input, and making conditional decisions based on that input, all within the app:ready event context.

Common Pitfalls & Troubleshooting

  1. Forgetting await for Puter.ui methods:

    • Pitfall: Calling Puter.ui.prompt() or Puter.ui.confirm() without await will cause your code to continue executing immediately, before the user has provided input or made a decision. This can lead to unexpected behavior or undefined values.
    • Solution: Always use await when calling asynchronous Puter.js APIs (those that return Promises), and ensure your surrounding function is marked async.
    • Example (incorrect): const name = Puter.ui.prompt("Name?"); console.log(name); // name will be a Promise, not the string!
    • Example (correct): const name = await Puter.ui.prompt("Name?"); console.log(name);
  2. Running Puter.js code outside the Puter.js environment:

    • Pitfall: If you try to run your script.js directly in a standard web browser (e.g., by opening index.html without puter run), the Puter global object will not exist, leading to ReferenceError: Puter is not defined.
    • Solution: Always launch your Puter.js applications using the puter run command (or deploy them to a Puter.js instance). The Puter global object is injected by the Puter.js runtime.
  3. Incorrect Event Names:

    • Pitfall: Typos in event names (e.g., Puter.events.on('appready', ...) instead of app:ready). The event listener simply won’t fire, and your code might appear to do nothing.
    • Solution: Double-check the official Puter.js documentation for the exact event names. Use console logs inside your event listeners to confirm they are being triggered.

Summary

In this chapter, you’ve taken a significant leap forward in your Puter.js journey!

Here are the key takeaways:

  • The Puter global object is the central entry point for all Puter.js core APIs.
  • The Puter.system module allows you to retrieve information about the Puter.js Web OS environment using Puter.system.info() and Puter.system.version.
  • The Puter.ui module provides standardized dialogs for user interaction: Puter.ui.alert(), Puter.ui.prompt(), and Puter.ui.confirm(). All Puter.ui methods return Promises and should be awaited.
  • The Puter.events module enables event-driven programming with Puter.events.on(), allowing your app to react to system and application lifecycle events like app:ready.
  • Using async/await is crucial for handling the asynchronous nature of many Puter.js APIs, ensuring your code executes in the correct order.
  • Always ensure your Puter.js application is running within the Puter.js environment to prevent Puter is not defined errors.

You’ve now built a solid foundation for interacting with the Puter.js Web OS. In the next chapter, we’ll dive into one of the most critical aspects of any operating system: File System Access. Get ready to learn how your apps can read, write, and manage files within the Puter.js user space!

References


This page is AI-assisted and reviewed. It references official documentation and recognized resources where relevant.