Skip to main content

Overview

The Aurora OS browser runtime uses an embedded app catalog (STORE_CATALOG array in os.js). This is a client-side repository — no server required for the PWA deployment. All apps are bundled with the OS and installed on-demand.
The embedded catalog model makes Aurora OS work completely offline as a Progressive Web App, with instant app installations requiring no network requests.

Repository Model

Embedded Catalog

The STORE_CATALOG is a JavaScript array containing all available apps:
Store Catalog Structure
const STORE_CATALOG = [
  {
    id: 'clock-app',
    name: 'World Clock',
    icon: 'clock',
    color: 'linear-gradient(135deg,#1a2040,#0d1530)',
    cat: 'Utilities',
    size: '2 KB',
    rating: 4.5,
    desc: 'Multiple timezone clocks with analog display.',
    run: function() { /* ... */ }
  },
  {
    id: 'weather-app',
    name: 'Weather',
    icon: 'weather',
    color: 'linear-gradient(135deg,#1a3050,#0d2040)',
    cat: 'Utilities',
    size: '3 KB',
    rating: 4.2,
    desc: 'Local weather display with forecast.',
    run: function() { /* ... */ }
  },
  // ... more apps
];

Installation State

Installed apps are tracked in localStorage:
Installation Tracking
const installedApps = JSON.parse(
  localStorage.getItem('aurora-installed-apps') || '[]'
);
// Example: ['clock-app', 'notes-app', 'todo-app']

function isInstalled(id) {
  return installedApps.includes(id);
}

Runtime Registry

On boot, installed apps are merged into the APPS array:
Boot-time Synchronization
STORE_CATALOG.forEach(a => {
  if (isInstalled(a.id) && !APPS.find(x => x.id === a.id)) {
    APPS.push({
      id: a.id,
      name: a.name,
      icon: a.icon,
      color: a.color,
      action: a.run
    });
  }
});

Catalog Structure

Each catalog entry is a complete app manifest:
id
string
required
Unique package identifier (e.g., clock-app, notes-app)
name
string
required
Human-readable app name (e.g., World Clock, Sticky Notes)
icon
string
required
Key into ICONS SVG registry (e.g., clock, note, palette)
color
string
required
CSS gradient for icon background
color: 'linear-gradient(135deg,#1a2040,#0d1530)'
cat
string
required
Category: Utilities, Productivity, Creative, Entertainment, or Games
size
string
required
Approximate bundle size (e.g., 2 KB, 4 KB)
rating
number
required
Star rating from 1.0 to 5.0
desc
string
required
Short description for the App Store card
run
function
required
App entry point that creates window and initializes app

Category System

Apps are organized into five categories for browsing and filtering:
Utilities
category
Purpose: System tools (clocks, weather, etc.)Examples: World Clock, Weather, Image ViewerTypical Use: Enhance OS functionality with utility apps
Productivity
category
Purpose: Work tools (notes, tasks, timers)Examples: Sticky Notes, Tasks, Pomodoro TimerTypical Use: Task management and focus enhancement
Creative
category
Purpose: Drawing and design toolsExamples: Aurora PaintTypical Use: Digital art and creative expression
Entertainment
category
Purpose: Media and ambient soundsExamples: Aurora RadioTypical Use: Relaxation and background ambience
Games
category
Purpose: Lightweight browser gamesExamples: SnakeTypical Use: Quick gaming sessions

Category Distribution

The current catalog contains:
Category Breakdown
const categories = [...new Set(STORE_CATALOG.map(a => a.cat))];
// Returns: ['Utilities', 'Productivity', 'Creative', 'Entertainment', 'Games']

// Count by category
Utilities:      3 apps  (World Clock, Weather, Image Viewer)
Productivity:   3 apps  (Sticky Notes, Tasks, Pomodoro Timer)
Creative:       1 app   (Aurora Paint)
Entertainment:  1 app   (Aurora Radio)
Games:          1 app   (Snake)

Installation Flow

When a user installs an app from the catalog:
1

Check Installation Status

Verify the app is not already installed by checking installedApps.includes(id).
2

Add to Installed List

Push app ID to the installedApps array in memory.
installedApps.push(id);
3

Persist to Storage

Serialize and save the updated array to localStorage.
localStorage.setItem('aurora-installed-apps', JSON.stringify(installedApps));
4

Register in Runtime

Find the app in STORE_CATALOG and add it to the APPS runtime registry.
const app = STORE_CATALOG.find(a => a.id === id);
if (app) {
  APPS.push({
    id: app.id,
    name: app.name,
    icon: app.icon,
    color: app.color,
    action: app.run
  });
}
5

Show Notification

Display a success notification to the user.
notify('Installed', `${app.name} installed successfully`, 'download', 'var(--success)');

Complete Installation Function

installApp Implementation
function installApp(id) {
  // Skip if already installed
  if (!isInstalled(id)) {
    // Add to installed list
    installedApps.push(id);
    
    // Persist to localStorage
    localStorage.setItem('aurora-installed-apps', JSON.stringify(installedApps));
    
    // Find app in catalog
    const app = STORE_CATALOG.find(a => a.id === id);
    
    // Register in runtime
    if (app) {
      APPS.push({
        id: app.id,
        name: app.name,
        icon: app.icon,
        color: app.color,
        action: app.run
      });
    }
    
    // Notify user
    notify('Installed', `${app?.name || id} installed successfully`, 'download', 'var(--success)');
  }
}

Uninstallation Flow

When a user removes an app:
1

Remove from Installed List

Find and remove the app ID from installedApps.
const idx = installedApps.indexOf(id);
if (idx >= 0) {
  installedApps.splice(idx, 1);
}
2

Update Storage

Save the updated list to localStorage.
localStorage.setItem('aurora-installed-apps', JSON.stringify(installedApps));
3

Unregister from Runtime

Remove the app from the APPS array.
const ai = APPS.findIndex(a => a.id === id);
if (ai >= 0) {
  APPS.splice(ai, 1);
}
4

Close Open Windows

If the app window is currently open, close it.
if (wins[id]) {
  closeWindow(id);
}
5

Show Notification

Confirm the removal to the user.
notify('Removed', 'App removed', 'trash', 'var(--muted)');

Complete Uninstallation Function

uninstallApp Implementation
function uninstallApp(id) {
  // Remove from installed list
  const idx = installedApps.indexOf(id);
  if (idx >= 0) {
    installedApps.splice(idx, 1);
    localStorage.setItem('aurora-installed-apps', JSON.stringify(installedApps));
  }
  
  // Remove from runtime registry
  const ai = APPS.findIndex(a => a.id === id);
  if (ai >= 0) {
    APPS.splice(ai, 1);
  }
  
  // Close window if open
  if (wins[id]) {
    closeWindow(id);
  }
  
  // Notify user
  notify('Removed', 'App removed', 'trash', 'var(--muted)');
}

Catalog Queries

The App Store UI performs various queries on the catalog:

List All Apps

const allApps = STORE_CATALOG;

Filter by Category

const utilities = STORE_CATALOG.filter(a => a.cat === 'Utilities');
const productivity = STORE_CATALOG.filter(a => a.cat === 'Productivity');

Filter by Installation Status

const installed = STORE_CATALOG.filter(a => isInstalled(a.id));
const available = STORE_CATALOG.filter(a => !isInstalled(a.id));

Search by Name or Description

function searchApps(query) {
  const q = query.toLowerCase();
  return STORE_CATALOG.filter(a => 
    a.name.toLowerCase().includes(q) || 
    a.desc.toLowerCase().includes(q)
  );
}

Get App by ID

function getApp(id) {
  return STORE_CATALOG.find(a => a.id === id);
}

CLI Integration

The terminal store command interacts with the catalog:
Terminal Store Command
store: (args) => {
  if (!args[0]) return 'Usage: store list | store install <app> | store remove <app> | store run <app>';
  
  // List all apps with install status
  if (args[0] === 'list') {
    return STORE_CATALOG.map(x => 
      `${isInstalled(x.id) ? '[✓]' : '[ ]'} ${x.id.padEnd(16)} ${x.name.padEnd(18)} ${x.cat}`
    ).join('\n');
  }
  
  // Search apps
  if (args[0] === 'search' && args[1]) {
    return STORE_CATALOG
      .filter(x => 
        x.name.toLowerCase().includes(args[1].toLowerCase()) || 
        x.id.includes(args[1])
      )
      .map(x => `${isInstalled(x.id) ? '[✓]' : '[ ]'} ${x.id.padEnd(16)} ${x.name}`)
      .join('\n') || 'No apps found';
  }
  
  // Install app
  if (args[0] === 'install' && args[1]) {
    const app = STORE_CATALOG.find(x => x.id === args[1] || x.id === args[1] + '-app');
    if (!app) return `store: package '${args[1]}' not found`;
    if (isInstalled(app.id)) return `${app.name} is already installed`;
    installApp(app.id);
    return `Installed ${app.name} (${app.size})`;
  }
  
  // Remove app
  if (args[0] === 'remove' && args[1]) {
    const app = STORE_CATALOG.find(x => x.id === args[1] || x.id === args[1] + '-app');
    if (!app) return `store: package '${args[1]}' not found`;
    if (!isInstalled(app.id)) return `${app.name} is not installed`;
    uninstallApp(app.id);
    return `Removed ${app.name}`;
  }
  
  // Run app
  if (args[0] === 'run' && args[1]) {
    const app = STORE_CATALOG.find(x => x.id === args[1] || x.id === args[1] + '-app');
    if (!app) return `store: package '${args[1]}' not found`;
    if (!isInstalled(app.id)) return `${app.name} is not installed. Run: store install ${app.id}`;
    app.run();
    return `Launching ${app.name}...`;
  }
  
  return 'Usage: store list | store install <app> | store remove <app> | store run <app>';
}

Current Catalog Contents

The embedded catalog contains 9 apps:
[
  { id: 'clock-app', name: 'World Clock', size: '2 KB', rating: 4.5 },
  { id: 'weather-app', name: 'Weather', size: '3 KB', rating: 4.2 },
  { id: 'imgview-app', name: 'Image Viewer', size: '2 KB', rating: 4.2 }
]

Future: Remote Repository

For native Aurora OS (beyond the browser runtime), a remote package repository will be implemented:
The remote repository will use the package server at /userland/pkg-server/ to serve signed packages over HTTPS with TUF-compliant metadata for secure updates.

Planned Remote Features

Signed Packages

Packages signed with cryptographic signatures for authenticity verification

TUF Metadata

The Update Framework (TUF) for secure, resilient package updates

HTTPS Delivery

Secure package delivery over encrypted connections

Remote Manifest

Fetch catalog from remote JSON manifest instead of embedded array

Migration Path

The browser runtime catalog can be extended to support remote repositories:
Remote Catalog Extension
// Current: embedded catalog
const STORE_CATALOG = [ /* apps */ ];

// Future: remote catalog
async function fetchCatalog() {
  const response = await fetch('https://packages.aurora-os.dev/catalog.json');
  const remoteCatalog = await response.json();
  
  // Verify signatures
  for (const app of remoteCatalog) {
    if (!verifySignature(app)) {
      console.warn(`Invalid signature for ${app.id}`);
      continue;
    }
    STORE_CATALOG.push(app);
  }
}

Repository Statistics

Catalog Metrics
Total Apps:          9
Total Categories:    5
Average Rating:      4.4 stars
Average Size:        2.4 KB
Smallest App:        2 KB (multiple)
Largest App:         4 KB (Aurora Paint)
Highest Rated:       4.8 stars (Snake)

Next Steps

Package Spec

Learn about the app manifest format and development patterns

Overview

Return to Package Manager overview

Build docs developers (and LLMs) love