npm package: @ravenstudiosio/laptop-sdk
Description: SDK for building apps for our FiveM laptop resource.
Author: ravenstudiosio
Latest version: 1.0.0

# Laptop SDK

Official SDK for building apps for our FiveM laptop resource.

[![npm version](https://img.shields.io/npm/v/@ravenstudiosio/laptop-sdk.svg)](https://www.npmjs.com/package/@ravenstudiosio/laptop-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Installation

```bash
npm install @ravenstudiosio/laptop-sdk
```

## Quick Start

### Method 1: Using Hooks with Context Provider (Recommended)

```tsx
import {
  createApp,
  RavenStudiosSDKProvider,
  useFileSystemAPI,
  useNotificationAPI,
} from "@ravenstudiosio/laptop-sdk";
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { Calculator } from "lucide-react";

// Child component can use hooks
const CalculatorContent = () => {
  const fileSystemApi = useFileSystemAPI();
  const notificationApi = useNotificationAPI();

  const handleCalculate = () => {
    fileSystemApi.createFile("/Home", "result.txt", "2 + 2 = 4");
    notificationApi.notify({
      title: "Calculation Complete",
      message: "Result saved to file",
    });
  };

  return (
    <div className="p-4">
      <h1>Calculator</h1>
      <button onClick={handleCalculate}>Calculate & Save</button>
    </div>
  );
};

// Wrap with provider to enable hooks
const component = (props: AppComponentProps) => {
  return (
    <RavenStudiosSDKProvider value={props}>
      <CalculatorContent />
    </RavenStudiosSDKProvider>
  );
};

export default createApp(
  {
    id: "my-calculator",
    name: "Calculator",
    icon: Calculator,
    category: "Utilities",
    description: "A simple calculator app",
    version: "1.0.0",
    isSystem: false,
    isDownloadable: true,
    downloadSize: 2.5,
    publisher: "Your Name",
    defaultWidth: 400,
    defaultHeight: 500,
  },
  component
);
```

### Method 2: Using Props (Traditional)

```tsx
import { createApp } from "@ravenstudiosio/laptop-sdk";
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { Calculator } from "lucide-react";

const MyCalculatorApp = ({
  windowApi,
  fileSystemApi,
  notificationApi,
}: AppComponentProps) => {
  const handleCalculate = () => {
    notificationApi.notify({
      title: "Calculation Complete",
      message: "2 + 2 = 4",
    });
  };

  return (
    <div className="p-4">
      <h1>Calculator</h1>
      <button onClick={handleCalculate}>Calculate</button>
    </div>
  );
};

export default createApp(
  {
    id: "my-calculator",
    name: "Calculator",
    icon: Calculator,
    category: "Utilities",
    description: "A simple calculator app",
    version: "1.0.0",
    isSystem: false,
    isDownloadable: true,
    downloadSize: 2.5,
    publisher: "Your Name",
    defaultWidth: 400,
    defaultHeight: 500,
  },
  MyCalculatorApp
);
```

### Method 3: Using Classic Export Pattern

```tsx
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { FileText } from "lucide-react";

const MyTextEditor = (props: AppComponentProps) => {
  return <div>Text Editor Content</div>;
};

const metadata = {
  id: "text-editor",
  name: "Text Editor",
  icon: FileText,
  category: "Productivity" as const,
  description: "Simple text editor",
  version: "1.0.0",
  isSystem: false,
  isDownloadable: true,
};

const component = (props: AppComponentProps) => {
  return <MyTextEditor {...props} />;
};

export default {
  metadata,
  component,
};
```

## React Hooks API

The SDK provides React hooks for a modern, ergonomic developer experience. Use these hooks to access SDK APIs anywhere in your component tree without prop drilling.

### Available Hooks

- `useSDK()` - Access all SDK APIs at once
- `useWindowAPI()` - Window management
- `useFileSystemAPI()` - File system operations
- `useStorageAPI()` - App-scoped storage
- `useDialogAPI()` - System dialogs
- `useClipboardAPI()` - Clipboard operations
- `useMenuAPI()` - Context menus
- `useShortcutAPI()` - Keyboard shortcuts
- `useIPCAPI()` - Inter-process communication
- `useNotificationAPI()` - Toast notifications
- `useSystemAPI()` - System information
- `useCommandAPI()` - Command palette
- `useProcessAPI()` - Process management
- `useAppInfo()` - App metadata

### Using Hooks

```tsx
import {
  RavenStudiosSDKProvider,
  useFileSystemAPI,
  useNotificationAPI,
  useWindowAPI,
} from "@ravenstudiosio/laptop-sdk";

// Deeply nested component
const SaveButton = () => {
  const fileSystemApi = useFileSystemAPI();
  const notificationApi = useNotificationAPI();

  const handleSave = () => {
    fileSystemApi.createFile("/Home", "data.txt", "My data");
    notificationApi.notify({
      title: "Saved",
      message: "File saved successfully",
    });
  };

  return <button onClick={handleSave}>Save</button>;
};

const Toolbar = () => {
  const windowApi = useWindowAPI();

  return (
    <div>
      <SaveButton />
      <button onClick={() => windowApi.maximize()}>Maximize</button>
    </div>
  );
};

// Root component wraps with provider
const component = (props: AppComponentProps) => {
  return (
    <RavenStudiosSDKProvider value={props}>
      <div>
        <h1>My App</h1>
        <Toolbar />
      </div>
    </RavenStudiosSDKProvider>
  );
};
```

### Hook Usage Examples

**useSDK** - Get all APIs:

```tsx
const MyComponent = () => {
  const { windowApi, fileSystemApi, notificationApi } = useSDK();
  // Use any API you need
};
```

**useSystemAPI** - React to theme changes:

```tsx
const ThemeDisplay = () => {
  const systemApi = useSystemAPI();
  const [theme, setTheme] = useState(systemApi.getTheme());

  useEffect(() => {
    return systemApi.onThemeChange(setTheme);
  }, [systemApi]);

  return <div>Current theme: {theme}</div>;
};
```

**useShortcutAPI** - Register keyboard shortcuts:

```tsx
const ShortcutExample = () => {
  const shortcutApi = useShortcutAPI();
  const notificationApi = useNotificationAPI();

  useEffect(() => {
    const unregister = shortcutApi.register(
      "Ctrl+S",
      () =>
        notificationApi.notify({ title: "Save", message: "Ctrl+S pressed!" }),
      { description: "Save file", global: true }
    );
    return unregister;
  }, [shortcutApi, notificationApi]);

  return <div>Press Ctrl+S</div>;
};
```

**useIPCAPI** - Inter-app communication:

```tsx
const IPCExample = () => {
  const ipcApi = useIPCAPI();
  const [messages, setMessages] = useState<string[]>([]);

  useEffect(() => {
    return ipcApi.on("chat", (data, senderAppId) => {
      setMessages((prev) => [...prev, `${senderAppId}: ${data}`]);
    });
  }, [ipcApi]);

  const sendMessage = () => {
    ipcApi.broadcast("chat", "Hello from my app!");
  };

  return (
    <div>
      <button onClick={sendMessage}>Send Message</button>
      <ul>
        {messages.map((m, i) => (
          <li key={i}>{m}</li>
        ))}
      </ul>
    </div>
  );
};
```

## Available APIs

The SDK provides 13 powerful APIs to interact with the laptop system:

### 1. Window API

Manage windows, dialogs, and file pickers.

```tsx
const MyApp = ({ windowApi }: AppComponentProps) => {
  const openNewWindow = () => {
    windowApi.openWindow("New Window", <div>Content</div>, 800, 600);
  };

  const closeApp = () => {
    windowApi.close();
  };

  const maximizeWindow = () => {
    windowApi.maximize();
  };

  return (
    <div>
      <button onClick={openNewWindow}>Open Window</button>
      <button onClick={maximizeWindow}>Maximize</button>
      <button onClick={closeApp}>Close</button>
    </div>
  );
};
```

### 2. File System API

Read, write, and manage files and folders.

```tsx
const MyApp = ({ fileSystemApi, notificationApi }: AppComponentProps) => {
  const createFile = () => {
    fileSystemApi.createFile("/Home", "document.txt", "Hello World");
    notificationApi.notify({
      title: "File Created",
      message: "document.txt created successfully",
    });
  };

  const readFile = () => {
    const file = fileSystemApi.getItemByPath("/Home/document.txt");
    if (file && file.type === "file") {
      console.log("Content:", file.content);
    }
  };

  const searchFiles = () => {
    const results = fileSystemApi.searchItems("document");
    console.log("Found:", results);
  };

  return (
    <div>
      <button onClick={createFile}>Create File</button>
      <button onClick={readFile}>Read File</button>
      <button onClick={searchFiles}>Search</button>
    </div>
  );
};
```

### 3. Storage API

App-scoped persistent storage (in-memory).

```tsx
const MyApp = ({ storageApi }: AppComponentProps) => {
  const saveData = () => {
    storageApi.set("user-preference", { theme: "dark", fontSize: 14 });
  };

  const loadData = () => {
    const prefs = storageApi.get("user-preference", { theme: "light" });
    console.log("Preferences:", prefs);
  };

  const clearData = () => {
    storageApi.clear();
  };

  return (
    <div>
      <button onClick={saveData}>Save</button>
      <button onClick={loadData}>Load</button>
      <button onClick={clearData}>Clear All</button>
    </div>
  );
};
```

### 4. Dialog API

System dialogs for user interaction.

```tsx
const MyApp = ({ dialogApi, notificationApi }: AppComponentProps) => {
  const showAlert = async () => {
    await dialogApi.alert({
      title: "Information",
      message: "This is an informational message",
    });
  };

  const showConfirm = async () => {
    const confirmed = await dialogApi.confirm({
      title: "Delete File?",
      message: "This action cannot be undone.",
    });
    if (confirmed) {
      console.log("User confirmed");
    }
  };

  const showPrompt = async () => {
    const name = await dialogApi.prompt({
      title: "Enter your name:",
      defaultValue: "John Doe",
    });
    if (name) {
      notificationApi.notify({
        title: "Hello",
        message: `Welcome, ${name}!`,
      });
    }
  };

  return (
    <div>
      <button onClick={showAlert}>Alert</button>
      <button onClick={showConfirm}>Confirm</button>
      <button onClick={showPrompt}>Prompt</button>
    </div>
  );
};
```

### 5. Clipboard API

Copy and paste functionality.

```tsx
const MyApp = ({ clipboardApi, notificationApi }: AppComponentProps) => {
  const copyText = () => {
    clipboardApi.writeText("Hello from Virtual OS!");
    notificationApi.notify({
      title: "Copied",
      message: "Text copied to clipboard",
    });
  };

  const pasteText = () => {
    const text = clipboardApi.readText();
    console.log("Pasted:", text);
  };

  return (
    <div>
      <button onClick={copyText}>Copy</button>
      <button onClick={pasteText}>Paste</button>
    </div>
  );
};
```

### 6. Notification API

Toast notifications.

```tsx
const MyApp = ({ notificationApi }: AppComponentProps) => {
  const showNotification = () => {
    notificationApi.notify({
      title: "Success",
      message: "Operation completed successfully",
    });
  };

  return <button onClick={showNotification}>Notify</button>;
};
```

### 7. Menu API

Context menus.

```tsx
const MyApp = ({ menuApi }: AppComponentProps) => {
  const showMenu = (e: React.MouseEvent) => {
    menuApi.showContextMenu(
      [
        { id: "cut", label: "Cut", onClick: () => console.log("Cut") },
        { id: "copy", label: "Copy", onClick: () => console.log("Copy") },
        { id: "sep", label: "", type: "separator" },
        { id: "paste", label: "Paste", onClick: () => console.log("Paste") },
      ],
      { x: e.clientX, y: e.clientY }
    );
  };

  return <div onContextMenu={showMenu}>Right-click me</div>;
};
```

### 8. Shortcut API

Global keyboard shortcuts.

```tsx
const MyApp = ({ shortcutApi, notificationApi }: AppComponentProps) => {
  useEffect(() => {
    const unregister = shortcutApi.register(
      "Ctrl+S",
      () => {
        notificationApi.notify({
          title: "Save",
          message: "File saved!",
        });
      },
      { description: "Save file", global: true }
    );

    return unregister;
  }, [shortcutApi, notificationApi]);

  return <div>Press Ctrl+S to save</div>;
};
```

### 9. IPC API

Inter-process communication between apps.

```tsx
const MyApp = ({ ipcApi, notificationApi }: AppComponentProps) => {
  useEffect(() => {
    // Listen for messages
    const unsubscribe = ipcApi.on("my-channel", (data, senderAppId) => {
      console.log("Received from", senderAppId, ":", data);
    });

    return unsubscribe;
  }, [ipcApi]);

  const sendMessage = () => {
    ipcApi.broadcast("my-channel", {
      message: "Hello from my app!",
      timestamp: Date.now(),
    });
  };

  return <button onClick={sendMessage}>Send Message</button>;
};
```

### 10. System API

System information and theme.

```tsx
const MyApp = ({ systemApi }: AppComponentProps) => {
  const [theme, setTheme] = useState(systemApi.getTheme());

  useEffect(() => {
    const unsubscribe = systemApi.onThemeChange((newTheme) => {
      setTheme(newTheme);
    });
    return unsubscribe;
  }, [systemApi]);

  const launchApp = () => {
    systemApi.launchApp("file-explorer");
  };

  return (
    <div>
      <p>Current theme: {theme}</p>
      <button onClick={launchApp}>Open File Explorer</button>
    </div>
  );
};
```

### 11. Command API

Register commands in the command palette.

```tsx
const MyApp = ({ commandApi }: AppComponentProps) => {
  useEffect(() => {
    commandApi.registerCommands([
      {
        id: "my-app-action",
        label: "Do Something Cool",
        description: "Performs a cool action",
        execute: () => {
          console.log("Command executed!");
        },
      },
    ]);

    return () => {
      commandApi.unregisterCommands(["my-app-action"]);
    };
  }, [commandApi]);

  return <div>Press Ctrl+K and search for "Do Something Cool"</div>;
};
```

### 12. Process API

Process and instance management.

```tsx
const MyApp = ({ processApi }: AppComponentProps) => {
  const info = processApi.getInfo();

  return (
    <div>
      <p>Instance ID: {info.instanceId}</p>
      <p>App ID: {info.appId}</p>
      <p>Started: {new Date(info.startTime).toLocaleString()}</p>
    </div>
  );
};
```

## TypeScript Support

The SDK is fully typed with TypeScript. All APIs have complete type definitions:

```tsx
import type {
  AppComponentProps,
  FileSystemItem,
  WindowState,
  SystemTheme,
  // ... and many more
} from "@ravenstudiosio/laptop-sdk";
```

## Building Your App

### Project Setup

1. Create a new React project with Vite:

```bash
npm create vite@latest my-virtual-os-app -- --template react-ts
cd my-virtual-os-app
npm install
```

2. Install the SDK and dependencies:

```bash
npm install @ravenstudiosio/laptop-sdk
npm install lucide-react
```

3. Configure Module Federation in `vite.config.ts`:

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { federation } from "@module-federation/vite";

export default defineConfig({
  server: {
    port: 5001,
    strictPort: true,
    origin: "http://localhost:5001",
  },
  base: "http://localhost:5001",
  plugins: [
    react(),
    federation({
      name: "my-app",
      filename: "remoteEntry.js",
      manifest: true,
      exposes: {
        "./app": "./src/AppModule.tsx",
      },
      shared: {
        react: { singleton: true, requiredVersion: "^19.0.0" },
        "react-dom": { singleton: true, requiredVersion: "^19.0.0" },
        "lucide-react": { singleton: true },
      },
    }),
  ],
  build: {
    modulePreload: false,
    target: "chrome89",
    minify: false,
    cssCodeSplit: false,
  },
});
```

4. Create your app in `src/AppModule.tsx`:

```tsx
import { createApp } from "@ravenstudiosio/laptop-sdk";
import type { AppComponentProps } from "@ravenstudiosio/laptop-sdk";
import { AppWindow } from "lucide-react";

const MyApp = (props: AppComponentProps) => {
  return (
    <div className="p-4">
      <h1>My Laptop App</h1>
    </div>
  );
};

export default createApp(
  {
    id: "my-app",
    name: "My App",
    icon: AppWindow,
    category: "Utilities",
    description: "My awesome app",
    version: "1.0.0",
    isSystem: false,
    isDownloadable: true,
  },
  MyApp
);
```